-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
174 lines (146 loc) · 4.92 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
'use strict';
var falafel = require('falafel-espree');
var Catalog = require('gettext-catalog');
var assign = require('lodash.assign');
function extract (source, gettextOptions, espreeOptions) {
gettextOptions = gettextOptions || {};
var filename = gettextOptions.filename;
var catalog = new Catalog(gettextOptions);
// Caller can turn off locations or extracting comments if they want
espreeOptions = assign({loc: true, attachComment: true}, espreeOptions);
falafel(source, espreeOptions, function (node) {
if (!node || node.type !== 'CallExpression' || !node.callee) {
// not the right kind of AST node
return;
}
var callee = node.callee;
var id;
if (callee.type === 'Identifier') {
// expressions like `gettext('Foo')`
id = callee.name;
} else if (callee.type === 'MemberExpression') {
if (!callee.property) {
return;
}
if (callee.property.type === 'Identifier') {
// i18n.gettext
id = callee.property.name;
} else if (callee.property.type === 'Literal') {
// i18n["gettext"]
id = callee.property.value;
} else {
return;
}
} else {
return;
}
if (Object.keys(catalog.identifiers).indexOf(id) === -1) {
// not a gettext function
return;
}
var spec = catalog.identifiers[id];
var params = node.arguments;
var msgidParam = params[spec.indexOf('msgid')];
if (!msgidParam) {
// don't extract gettext() without param
return;
}
var invalidMsgid;
var msgid = (function () {
var extractMsgid = function (node) {
if (invalidMsgid) {
// stop recursing if we already know this node isn't a valid msgid
return;
}
if (node.type === 'Literal') {
return node.value;
}
if (node.type === 'BinaryExpression' && node.operator === '+') {
return extractMsgid(node.left) + extractMsgid(node.right);
}
// common example of this is something like
// gettext('Hello ' + user),
// i.e. where some part of msgid isn't a literal
invalidMsgid = true;
};
return extractMsgid(msgidParam);
})();
if (!msgid || invalidMsgid) {
return;
}
var contextIndex = spec.indexOf('msgctxt');
var context = null; // null context is *not* the same as empty context
if (contextIndex >= 0) {
var contextParam = params[contextIndex];
if (!contextParam) {
// throw an error if there's supposed to be a context but not enough
// parameters were passed to the handlebars helper
throw new Error('Expected a context for msgid "' + msgid + '" but none was given');
}
if (contextParam.type !== 'Literal') {
throw new Error('Context must be a string literal (msgid "' + msgid + '")');
}
context = contextParam.value;
}
var domain = catalog.defaultDomain;
var domainIndex = spec.indexOf('domain');
if (domainIndex !== -1) {
var domainParam = params[domainIndex];
if (!domainParam) {
throw new Error('Expected a domain for msgid "' + msgid + '" but none was given');
}
if (domainParam.type !== 'Literal') {
throw new Error('Domain must be a string literal (msgid "' + msgid + '")');
}
domain = domainParam.value;
}
// make sure plural forms match
var pluralIndex = spec.indexOf('msgid_plural');
var plural = null;
if (pluralIndex !== -1) {
var pluralParam = params[pluralIndex];
if (!pluralParam) {
throw new Error('No plural specified for msgid "' + msgid + '"');
}
if (pluralParam.type !== 'Literal') {
throw new Error('Plural must be a string literal for msgid ' + msgid);
}
plural = pluralParam.value;
}
var message = {};
message[domain] = {};
var key = catalog.messageToKey(msgid, context);
var loc = node.loc || {
// locations can be turned off to increase parse speed if users really want
start: {line: null, column: null},
end: {line: null, column: null}
};
message[domain][key] = {
msgid: msgid,
msgctxt: context,
msgid_plural: plural,
references: [
{
filename: filename,
firstLine: loc.start.line,
firstColumn: loc.start.column,
lastLine: loc.end.line,
lastColumn: loc.end.column
}
],
extractedComments: (function () {
var comments = node.leadingComments || (node.parent ? node.parent.leadingComments : []) || [];
return comments.reduce(function (comments, comment) {
if (comment.type === 'Line' && comment.value.indexOf('/') === 0) {
// comment of the form ///
comments.push(comment.value.substr(1).trim());
}
return comments;
}, []);
})()
};
catalog.addMessages(message);
});
return catalog;
}
module.exports = extract;