@intlify/message-compiler 11.1.2 → 12.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/message-compiler.d.ts +6 -2
- package/dist/message-compiler.esm-browser.js +549 -547
- package/dist/message-compiler.esm-browser.prod.js +3 -3
- package/dist/message-compiler.esm-bundler.js +1 -1
- package/dist/message-compiler.global.js +551 -547
- package/dist/message-compiler.global.prod.js +3 -3
- package/dist/{message-compiler.mjs → message-compiler.js} +397 -395
- package/dist/{message-compiler.node.mjs → message-compiler.node.js} +1186 -1184
- package/package.json +7 -15
- package/dist/message-compiler.cjs +0 -1587
- package/dist/message-compiler.cjs.js +0 -1
- package/dist/message-compiler.cjs.prod.js +0 -1
- package/dist/message-compiler.prod.cjs +0 -1570
- package/index.js +0 -7
|
@@ -1,23 +1,8 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* message-compiler
|
|
3
|
-
* (c)
|
|
2
|
+
* message-compiler v12.0.0-alpha.1
|
|
3
|
+
* (c) 2016-present kazuya kawaguchi and contributors
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
const LOCATION_STUB = {
|
|
7
|
-
start: { line: 1, column: 1, offset: 0 },
|
|
8
|
-
end: { line: 1, column: 1, offset: 0 }
|
|
9
|
-
};
|
|
10
|
-
function createPosition(line, column, offset) {
|
|
11
|
-
return { line, column, offset };
|
|
12
|
-
}
|
|
13
|
-
function createLocation(start, end, source) {
|
|
14
|
-
const loc = { start, end };
|
|
15
|
-
if (source != null) {
|
|
16
|
-
loc.source = source;
|
|
17
|
-
}
|
|
18
|
-
return loc;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
6
|
/**
|
|
22
7
|
* Original Utilities
|
|
23
8
|
* written by kazuya kawaguchi
|
|
@@ -43,6 +28,21 @@ function join(items, separator = '') {
|
|
|
43
28
|
return items.reduce((str, item, index) => (index === 0 ? str + item : str + separator + item), '');
|
|
44
29
|
}
|
|
45
30
|
|
|
31
|
+
const LOCATION_STUB = {
|
|
32
|
+
start: { line: 1, column: 1, offset: 0 },
|
|
33
|
+
end: { line: 1, column: 1, offset: 0 }
|
|
34
|
+
};
|
|
35
|
+
function createPosition(line, column, offset) {
|
|
36
|
+
return { line, column, offset };
|
|
37
|
+
}
|
|
38
|
+
function createLocation(start, end, source) {
|
|
39
|
+
const loc = { start, end };
|
|
40
|
+
if (source != null) {
|
|
41
|
+
loc.source = source;
|
|
42
|
+
}
|
|
43
|
+
return loc;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
46
|
const CompileErrorCodes = {
|
|
47
47
|
// tokenizer error codes
|
|
48
48
|
EXPECTED_TOKEN: 1,
|
|
@@ -109,164 +109,473 @@ function defaultOnError(error) {
|
|
|
109
109
|
throw error;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// eslint-disable-next-line
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index);
|
|
132
|
-
const index = () => _index;
|
|
133
|
-
const line = () => _line;
|
|
134
|
-
const column = () => _column;
|
|
135
|
-
const peekOffset = () => _peekOffset;
|
|
136
|
-
const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset];
|
|
137
|
-
const currentChar = () => charAt(_index);
|
|
138
|
-
const currentPeek = () => charAt(_index + _peekOffset);
|
|
139
|
-
function next() {
|
|
140
|
-
_peekOffset = 0;
|
|
141
|
-
if (isLineEnd(_index)) {
|
|
142
|
-
_line++;
|
|
143
|
-
_column = 0;
|
|
144
|
-
}
|
|
145
|
-
if (isCRLF(_index)) {
|
|
146
|
-
_index++;
|
|
147
|
-
}
|
|
148
|
-
_index++;
|
|
149
|
-
_column++;
|
|
150
|
-
return _buf[_index];
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
113
|
+
/// <reference types="source-map-js" />
|
|
114
|
+
const ERROR_DOMAIN$3 = 'parser';
|
|
115
|
+
function createCodeGenerator(ast, options) {
|
|
116
|
+
const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options;
|
|
117
|
+
const location = options.location !== false;
|
|
118
|
+
const _context = {
|
|
119
|
+
filename,
|
|
120
|
+
code: '',
|
|
121
|
+
column: 1,
|
|
122
|
+
line: 1,
|
|
123
|
+
offset: 0,
|
|
124
|
+
map: undefined,
|
|
125
|
+
breakLineCode,
|
|
126
|
+
needIndent: _needIndent,
|
|
127
|
+
indentLevel: 0
|
|
128
|
+
};
|
|
129
|
+
if (location && ast.loc) {
|
|
130
|
+
_context.source = ast.loc.source;
|
|
151
131
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
_peekOffset++;
|
|
157
|
-
return _buf[_index + _peekOffset];
|
|
132
|
+
const context = () => _context;
|
|
133
|
+
function push(code, node) {
|
|
134
|
+
_context.code += code;
|
|
158
135
|
}
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
_column = 1;
|
|
163
|
-
_peekOffset = 0;
|
|
136
|
+
function _newline(n, withBreakLine = true) {
|
|
137
|
+
const _breakLineCode = withBreakLine ? breakLineCode : '';
|
|
138
|
+
push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
|
|
164
139
|
}
|
|
165
|
-
function
|
|
166
|
-
|
|
140
|
+
function indent(withNewLine = true) {
|
|
141
|
+
const level = ++_context.indentLevel;
|
|
142
|
+
withNewLine && _newline(level);
|
|
167
143
|
}
|
|
168
|
-
function
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
144
|
+
function deindent(withNewLine = true) {
|
|
145
|
+
const level = --_context.indentLevel;
|
|
146
|
+
withNewLine && _newline(level);
|
|
147
|
+
}
|
|
148
|
+
function newline() {
|
|
149
|
+
_newline(_context.indentLevel);
|
|
174
150
|
}
|
|
151
|
+
const helper = (key) => `_${key}`;
|
|
152
|
+
const needIndent = () => _context.needIndent;
|
|
175
153
|
return {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
next,
|
|
184
|
-
peek,
|
|
185
|
-
reset,
|
|
186
|
-
resetPeek,
|
|
187
|
-
skipToPeek
|
|
154
|
+
context,
|
|
155
|
+
push,
|
|
156
|
+
indent,
|
|
157
|
+
deindent,
|
|
158
|
+
newline,
|
|
159
|
+
helper,
|
|
160
|
+
needIndent
|
|
188
161
|
};
|
|
189
162
|
}
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const currentOffset = () => _scnr.index();
|
|
199
|
-
const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index());
|
|
200
|
-
const _initLoc = currentPosition();
|
|
201
|
-
const _initOffset = currentOffset();
|
|
202
|
-
const _context = {
|
|
203
|
-
currentType: 13 /* TokenTypes.EOF */,
|
|
204
|
-
offset: _initOffset,
|
|
205
|
-
startLoc: _initLoc,
|
|
206
|
-
endLoc: _initLoc,
|
|
207
|
-
lastType: 13 /* TokenTypes.EOF */,
|
|
208
|
-
lastOffset: _initOffset,
|
|
209
|
-
lastStartLoc: _initLoc,
|
|
210
|
-
lastEndLoc: _initLoc,
|
|
211
|
-
braceNest: 0,
|
|
212
|
-
inLinked: false,
|
|
213
|
-
text: ''
|
|
214
|
-
};
|
|
215
|
-
const context = () => _context;
|
|
216
|
-
const { onError } = options;
|
|
217
|
-
function emitError(code, pos, offset, ...args) {
|
|
218
|
-
const ctx = context();
|
|
219
|
-
pos.column += offset;
|
|
220
|
-
pos.offset += offset;
|
|
221
|
-
if (onError) {
|
|
222
|
-
const loc = location ? createLocation(ctx.startLoc, pos) : null;
|
|
223
|
-
const err = createCompileError(code, loc, {
|
|
224
|
-
domain: ERROR_DOMAIN$3,
|
|
225
|
-
args
|
|
226
|
-
});
|
|
227
|
-
onError(err);
|
|
228
|
-
}
|
|
163
|
+
function generateLinkedNode(generator, node) {
|
|
164
|
+
const { helper } = generator;
|
|
165
|
+
generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`);
|
|
166
|
+
generateNode(generator, node.key);
|
|
167
|
+
if (node.modifier) {
|
|
168
|
+
generator.push(`, `);
|
|
169
|
+
generateNode(generator, node.modifier);
|
|
170
|
+
generator.push(`, _type`);
|
|
229
171
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
context.currentType = type;
|
|
233
|
-
const token = { type };
|
|
234
|
-
if (location) {
|
|
235
|
-
token.loc = createLocation(context.startLoc, context.endLoc);
|
|
236
|
-
}
|
|
237
|
-
if (value != null) {
|
|
238
|
-
token.value = value;
|
|
239
|
-
}
|
|
240
|
-
return token;
|
|
172
|
+
else {
|
|
173
|
+
generator.push(`, undefined, _type`);
|
|
241
174
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
175
|
+
generator.push(`)`);
|
|
176
|
+
}
|
|
177
|
+
function generateMessageNode(generator, node) {
|
|
178
|
+
const { helper, needIndent } = generator;
|
|
179
|
+
generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`);
|
|
180
|
+
generator.indent(needIndent());
|
|
181
|
+
const length = node.items.length;
|
|
182
|
+
for (let i = 0; i < length; i++) {
|
|
183
|
+
generateNode(generator, node.items[i]);
|
|
184
|
+
if (i === length - 1) {
|
|
185
|
+
break;
|
|
251
186
|
}
|
|
187
|
+
generator.push(', ');
|
|
252
188
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
189
|
+
generator.deindent(needIndent());
|
|
190
|
+
generator.push('])');
|
|
191
|
+
}
|
|
192
|
+
function generatePluralNode(generator, node) {
|
|
193
|
+
const { helper, needIndent } = generator;
|
|
194
|
+
if (node.cases.length > 1) {
|
|
195
|
+
generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`);
|
|
196
|
+
generator.indent(needIndent());
|
|
197
|
+
const length = node.cases.length;
|
|
198
|
+
for (let i = 0; i < length; i++) {
|
|
199
|
+
generateNode(generator, node.cases[i]);
|
|
200
|
+
if (i === length - 1) {
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
generator.push(', ');
|
|
258
204
|
}
|
|
259
|
-
|
|
205
|
+
generator.deindent(needIndent());
|
|
206
|
+
generator.push(`])`);
|
|
260
207
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
208
|
+
}
|
|
209
|
+
function generateResource(generator, node) {
|
|
210
|
+
if (node.body) {
|
|
211
|
+
generateNode(generator, node.body);
|
|
265
212
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
213
|
+
else {
|
|
214
|
+
generator.push('null');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function generateNode(generator, node) {
|
|
218
|
+
const { helper } = generator;
|
|
219
|
+
switch (node.type) {
|
|
220
|
+
case 0 /* NodeTypes.Resource */:
|
|
221
|
+
generateResource(generator, node);
|
|
222
|
+
break;
|
|
223
|
+
case 1 /* NodeTypes.Plural */:
|
|
224
|
+
generatePluralNode(generator, node);
|
|
225
|
+
break;
|
|
226
|
+
case 2 /* NodeTypes.Message */:
|
|
227
|
+
generateMessageNode(generator, node);
|
|
228
|
+
break;
|
|
229
|
+
case 6 /* NodeTypes.Linked */:
|
|
230
|
+
generateLinkedNode(generator, node);
|
|
231
|
+
break;
|
|
232
|
+
case 8 /* NodeTypes.LinkedModifier */:
|
|
233
|
+
generator.push(JSON.stringify(node.value), node);
|
|
234
|
+
break;
|
|
235
|
+
case 7 /* NodeTypes.LinkedKey */:
|
|
236
|
+
generator.push(JSON.stringify(node.value), node);
|
|
237
|
+
break;
|
|
238
|
+
case 5 /* NodeTypes.List */:
|
|
239
|
+
generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node);
|
|
240
|
+
break;
|
|
241
|
+
case 4 /* NodeTypes.Named */:
|
|
242
|
+
generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node);
|
|
243
|
+
break;
|
|
244
|
+
case 9 /* NodeTypes.Literal */:
|
|
245
|
+
generator.push(JSON.stringify(node.value), node);
|
|
246
|
+
break;
|
|
247
|
+
case 3 /* NodeTypes.Text */:
|
|
248
|
+
generator.push(JSON.stringify(node.value), node);
|
|
249
|
+
break;
|
|
250
|
+
default:
|
|
251
|
+
{
|
|
252
|
+
throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, {
|
|
253
|
+
domain: ERROR_DOMAIN$3,
|
|
254
|
+
args: [node.type]
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// generate code from AST
|
|
260
|
+
const generate = (ast, options = {}) => {
|
|
261
|
+
const mode = isString(options.mode) ? options.mode : 'normal';
|
|
262
|
+
const filename = isString(options.filename)
|
|
263
|
+
? options.filename
|
|
264
|
+
: 'message.intl';
|
|
265
|
+
const sourceMap = !!options.sourceMap;
|
|
266
|
+
// prettier-ignore
|
|
267
|
+
const breakLineCode = options.breakLineCode != null
|
|
268
|
+
? options.breakLineCode
|
|
269
|
+
: mode === 'arrow'
|
|
270
|
+
? ';'
|
|
271
|
+
: '\n';
|
|
272
|
+
const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
|
|
273
|
+
const helpers = ast.helpers || [];
|
|
274
|
+
const generator = createCodeGenerator(ast, {
|
|
275
|
+
mode,
|
|
276
|
+
filename,
|
|
277
|
+
sourceMap,
|
|
278
|
+
breakLineCode,
|
|
279
|
+
needIndent
|
|
280
|
+
});
|
|
281
|
+
generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
|
|
282
|
+
generator.indent(needIndent);
|
|
283
|
+
if (helpers.length > 0) {
|
|
284
|
+
generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`);
|
|
285
|
+
generator.newline();
|
|
286
|
+
}
|
|
287
|
+
generator.push(`return `);
|
|
288
|
+
generateNode(generator, ast);
|
|
289
|
+
generator.deindent(needIndent);
|
|
290
|
+
generator.push(`}`);
|
|
291
|
+
delete ast.helpers;
|
|
292
|
+
const { code, map } = generator.context();
|
|
293
|
+
return {
|
|
294
|
+
ast,
|
|
295
|
+
code,
|
|
296
|
+
map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const ERROR_DOMAIN$2 = 'minifier';
|
|
301
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
302
|
+
function mangle(node) {
|
|
303
|
+
node.t = node.type;
|
|
304
|
+
switch (node.type) {
|
|
305
|
+
case 0 /* NodeTypes.Resource */: {
|
|
306
|
+
const resource = node;
|
|
307
|
+
mangle(resource.body);
|
|
308
|
+
resource.b = resource.body;
|
|
309
|
+
delete resource.body;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
case 1 /* NodeTypes.Plural */: {
|
|
313
|
+
const plural = node;
|
|
314
|
+
const cases = plural.cases;
|
|
315
|
+
for (let i = 0; i < cases.length; i++) {
|
|
316
|
+
mangle(cases[i]);
|
|
317
|
+
}
|
|
318
|
+
plural.c = cases;
|
|
319
|
+
delete plural.cases;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case 2 /* NodeTypes.Message */: {
|
|
323
|
+
const message = node;
|
|
324
|
+
const items = message.items;
|
|
325
|
+
for (let i = 0; i < items.length; i++) {
|
|
326
|
+
mangle(items[i]);
|
|
327
|
+
}
|
|
328
|
+
message.i = items;
|
|
329
|
+
delete message.items;
|
|
330
|
+
if (message.static) {
|
|
331
|
+
message.s = message.static;
|
|
332
|
+
delete message.static;
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case 3 /* NodeTypes.Text */:
|
|
337
|
+
case 9 /* NodeTypes.Literal */:
|
|
338
|
+
case 8 /* NodeTypes.LinkedModifier */:
|
|
339
|
+
case 7 /* NodeTypes.LinkedKey */: {
|
|
340
|
+
const valueNode = node;
|
|
341
|
+
if (valueNode.value) {
|
|
342
|
+
valueNode.v = valueNode.value;
|
|
343
|
+
delete valueNode.value;
|
|
344
|
+
}
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
case 6 /* NodeTypes.Linked */: {
|
|
348
|
+
const linked = node;
|
|
349
|
+
mangle(linked.key);
|
|
350
|
+
linked.k = linked.key;
|
|
351
|
+
delete linked.key;
|
|
352
|
+
if (linked.modifier) {
|
|
353
|
+
mangle(linked.modifier);
|
|
354
|
+
linked.m = linked.modifier;
|
|
355
|
+
delete linked.modifier;
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case 5 /* NodeTypes.List */: {
|
|
360
|
+
const list = node;
|
|
361
|
+
list.i = list.index;
|
|
362
|
+
delete list.index;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
case 4 /* NodeTypes.Named */: {
|
|
366
|
+
const named = node;
|
|
367
|
+
named.k = named.key;
|
|
368
|
+
delete named.key;
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
default:
|
|
372
|
+
{
|
|
373
|
+
throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, {
|
|
374
|
+
domain: ERROR_DOMAIN$2,
|
|
375
|
+
args: [node.type]
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
delete node.type;
|
|
380
|
+
}
|
|
381
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
382
|
+
|
|
383
|
+
function optimize(ast) {
|
|
384
|
+
const body = ast.body;
|
|
385
|
+
if (body.type === 2 /* NodeTypes.Message */) {
|
|
386
|
+
optimizeMessageNode(body);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
body.cases.forEach(c => optimizeMessageNode(c));
|
|
390
|
+
}
|
|
391
|
+
return ast;
|
|
392
|
+
}
|
|
393
|
+
function optimizeMessageNode(message) {
|
|
394
|
+
if (message.items.length === 1) {
|
|
395
|
+
const item = message.items[0];
|
|
396
|
+
if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
|
|
397
|
+
message.static = item.value;
|
|
398
|
+
delete item.value; // optimization for size
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
const values = [];
|
|
403
|
+
for (let i = 0; i < message.items.length; i++) {
|
|
404
|
+
const item = message.items[i];
|
|
405
|
+
if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) {
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
if (item.value == null) {
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
values.push(item.value);
|
|
412
|
+
}
|
|
413
|
+
if (values.length === message.items.length) {
|
|
414
|
+
message.static = join(values);
|
|
415
|
+
for (let i = 0; i < message.items.length; i++) {
|
|
416
|
+
const item = message.items[i];
|
|
417
|
+
if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
|
|
418
|
+
delete item.value; // optimization for size
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const CHAR_SP = ' ';
|
|
426
|
+
const CHAR_CR = '\r';
|
|
427
|
+
const CHAR_LF = '\n';
|
|
428
|
+
const CHAR_LS = String.fromCharCode(0x2028);
|
|
429
|
+
const CHAR_PS = String.fromCharCode(0x2029);
|
|
430
|
+
function createScanner(str) {
|
|
431
|
+
const _buf = str;
|
|
432
|
+
let _index = 0;
|
|
433
|
+
let _line = 1;
|
|
434
|
+
let _column = 1;
|
|
435
|
+
let _peekOffset = 0;
|
|
436
|
+
const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF;
|
|
437
|
+
const isLF = (index) => _buf[index] === CHAR_LF;
|
|
438
|
+
const isPS = (index) => _buf[index] === CHAR_PS;
|
|
439
|
+
const isLS = (index) => _buf[index] === CHAR_LS;
|
|
440
|
+
const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index);
|
|
441
|
+
const index = () => _index;
|
|
442
|
+
const line = () => _line;
|
|
443
|
+
const column = () => _column;
|
|
444
|
+
const peekOffset = () => _peekOffset;
|
|
445
|
+
const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset];
|
|
446
|
+
const currentChar = () => charAt(_index);
|
|
447
|
+
const currentPeek = () => charAt(_index + _peekOffset);
|
|
448
|
+
function next() {
|
|
449
|
+
_peekOffset = 0;
|
|
450
|
+
if (isLineEnd(_index)) {
|
|
451
|
+
_line++;
|
|
452
|
+
_column = 0;
|
|
453
|
+
}
|
|
454
|
+
if (isCRLF(_index)) {
|
|
455
|
+
_index++;
|
|
456
|
+
}
|
|
457
|
+
_index++;
|
|
458
|
+
_column++;
|
|
459
|
+
return _buf[_index];
|
|
460
|
+
}
|
|
461
|
+
function peek() {
|
|
462
|
+
if (isCRLF(_index + _peekOffset)) {
|
|
463
|
+
_peekOffset++;
|
|
464
|
+
}
|
|
465
|
+
_peekOffset++;
|
|
466
|
+
return _buf[_index + _peekOffset];
|
|
467
|
+
}
|
|
468
|
+
function reset() {
|
|
469
|
+
_index = 0;
|
|
470
|
+
_line = 1;
|
|
471
|
+
_column = 1;
|
|
472
|
+
_peekOffset = 0;
|
|
473
|
+
}
|
|
474
|
+
function resetPeek(offset = 0) {
|
|
475
|
+
_peekOffset = offset;
|
|
476
|
+
}
|
|
477
|
+
function skipToPeek() {
|
|
478
|
+
const target = _index + _peekOffset;
|
|
479
|
+
while (target !== _index) {
|
|
480
|
+
next();
|
|
481
|
+
}
|
|
482
|
+
_peekOffset = 0;
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
index,
|
|
486
|
+
line,
|
|
487
|
+
column,
|
|
488
|
+
peekOffset,
|
|
489
|
+
charAt,
|
|
490
|
+
currentChar,
|
|
491
|
+
currentPeek,
|
|
492
|
+
next,
|
|
493
|
+
peek,
|
|
494
|
+
reset,
|
|
495
|
+
resetPeek,
|
|
496
|
+
skipToPeek
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const EOF = undefined;
|
|
501
|
+
const DOT = '.';
|
|
502
|
+
const LITERAL_DELIMITER = "'";
|
|
503
|
+
const ERROR_DOMAIN$1 = 'tokenizer';
|
|
504
|
+
function createTokenizer(source, options = {}) {
|
|
505
|
+
const location = options.location !== false;
|
|
506
|
+
const _scnr = createScanner(source);
|
|
507
|
+
const currentOffset = () => _scnr.index();
|
|
508
|
+
const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index());
|
|
509
|
+
const _initLoc = currentPosition();
|
|
510
|
+
const _initOffset = currentOffset();
|
|
511
|
+
const _context = {
|
|
512
|
+
currentType: 13 /* TokenTypes.EOF */,
|
|
513
|
+
offset: _initOffset,
|
|
514
|
+
startLoc: _initLoc,
|
|
515
|
+
endLoc: _initLoc,
|
|
516
|
+
lastType: 13 /* TokenTypes.EOF */,
|
|
517
|
+
lastOffset: _initOffset,
|
|
518
|
+
lastStartLoc: _initLoc,
|
|
519
|
+
lastEndLoc: _initLoc,
|
|
520
|
+
braceNest: 0,
|
|
521
|
+
inLinked: false,
|
|
522
|
+
text: ''
|
|
523
|
+
};
|
|
524
|
+
const context = () => _context;
|
|
525
|
+
const { onError } = options;
|
|
526
|
+
function emitError(code, pos, offset, ...args) {
|
|
527
|
+
const ctx = context();
|
|
528
|
+
pos.column += offset;
|
|
529
|
+
pos.offset += offset;
|
|
530
|
+
if (onError) {
|
|
531
|
+
const loc = location ? createLocation(ctx.startLoc, pos) : null;
|
|
532
|
+
const err = createCompileError(code, loc, {
|
|
533
|
+
domain: ERROR_DOMAIN$1,
|
|
534
|
+
args
|
|
535
|
+
});
|
|
536
|
+
onError(err);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function getToken(context, type, value) {
|
|
540
|
+
context.endLoc = currentPosition();
|
|
541
|
+
context.currentType = type;
|
|
542
|
+
const token = { type };
|
|
543
|
+
if (location) {
|
|
544
|
+
token.loc = createLocation(context.startLoc, context.endLoc);
|
|
545
|
+
}
|
|
546
|
+
if (value != null) {
|
|
547
|
+
token.value = value;
|
|
548
|
+
}
|
|
549
|
+
return token;
|
|
550
|
+
}
|
|
551
|
+
const getEndToken = (context) => getToken(context, 13 /* TokenTypes.EOF */);
|
|
552
|
+
function eat(scnr, ch) {
|
|
553
|
+
if (scnr.currentChar() === ch) {
|
|
554
|
+
scnr.next();
|
|
555
|
+
return ch;
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch);
|
|
559
|
+
return '';
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function peekSpaces(scnr) {
|
|
563
|
+
let buf = '';
|
|
564
|
+
while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) {
|
|
565
|
+
buf += scnr.currentPeek();
|
|
566
|
+
scnr.peek();
|
|
567
|
+
}
|
|
568
|
+
return buf;
|
|
569
|
+
}
|
|
570
|
+
function skipSpaces(scnr) {
|
|
571
|
+
const buf = peekSpaces(scnr);
|
|
572
|
+
scnr.skipToPeek();
|
|
573
|
+
return buf;
|
|
574
|
+
}
|
|
575
|
+
function isIdentifierStart(ch) {
|
|
576
|
+
if (ch === EOF) {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
270
579
|
const cc = ch.charCodeAt(0);
|
|
271
580
|
return ((cc >= 97 && cc <= 122) || // a-z
|
|
272
581
|
(cc >= 65 && cc <= 90) || // A-Z
|
|
@@ -842,7 +1151,7 @@ function createTokenizer(source, options = {}) {
|
|
|
842
1151
|
};
|
|
843
1152
|
}
|
|
844
1153
|
|
|
845
|
-
const ERROR_DOMAIN
|
|
1154
|
+
const ERROR_DOMAIN = 'parser';
|
|
846
1155
|
// Backslash backslash, backslash quote, uHHHH, UHHHHHH.
|
|
847
1156
|
const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
|
|
848
1157
|
function fromEscapeSequence(match, codePoint4, codePoint6) {
|
|
@@ -874,7 +1183,7 @@ function createParser(options = {}) {
|
|
|
874
1183
|
if (onError) {
|
|
875
1184
|
const loc = location ? createLocation(start, end) : null;
|
|
876
1185
|
const err = createCompileError(code, loc, {
|
|
877
|
-
domain: ERROR_DOMAIN
|
|
1186
|
+
domain: ERROR_DOMAIN,
|
|
878
1187
|
args
|
|
879
1188
|
});
|
|
880
1189
|
onError(err);
|
|
@@ -1107,420 +1416,109 @@ function createParser(options = {}) {
|
|
|
1107
1416
|
const context = tokenizer.context();
|
|
1108
1417
|
const { offset, startLoc } = context;
|
|
1109
1418
|
const msgNode = parseMessage(tokenizer);
|
|
1110
|
-
if (context.currentType === 13 /* TokenTypes.EOF */) {
|
|
1111
|
-
return msgNode;
|
|
1112
|
-
}
|
|
1113
|
-
else {
|
|
1114
|
-
return parsePlural(tokenizer, offset, startLoc, msgNode);
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
function parse(source) {
|
|
1118
|
-
const tokenizer = createTokenizer(source, assign({}, options));
|
|
1119
|
-
const context = tokenizer.context();
|
|
1120
|
-
const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc);
|
|
1121
|
-
if (location && node.loc) {
|
|
1122
|
-
node.loc.source = source;
|
|
1123
|
-
}
|
|
1124
|
-
node.body = parseResource(tokenizer);
|
|
1125
|
-
if (options.onCacheKey) {
|
|
1126
|
-
node.cacheKey = options.onCacheKey(source);
|
|
1127
|
-
}
|
|
1128
|
-
// assert whether achieved to EOF
|
|
1129
|
-
if (context.currentType !== 13 /* TokenTypes.EOF */) {
|
|
1130
|
-
emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || '');
|
|
1131
|
-
}
|
|
1132
|
-
endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
|
|
1133
|
-
return node;
|
|
1134
|
-
}
|
|
1135
|
-
return { parse };
|
|
1136
|
-
}
|
|
1137
|
-
function getTokenCaption(token) {
|
|
1138
|
-
if (token.type === 13 /* TokenTypes.EOF */) {
|
|
1139
|
-
return 'EOF';
|
|
1140
|
-
}
|
|
1141
|
-
const name = (token.value || '').replace(/\r?\n/gu, '\\n');
|
|
1142
|
-
return name.length > 10 ? name.slice(0, 9) + '…' : name;
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
function createTransformer(ast, options = {} // eslint-disable-line
|
|
1146
|
-
) {
|
|
1147
|
-
const _context = {
|
|
1148
|
-
ast,
|
|
1149
|
-
helpers: new Set()
|
|
1150
|
-
};
|
|
1151
|
-
const context = () => _context;
|
|
1152
|
-
const helper = (name) => {
|
|
1153
|
-
_context.helpers.add(name);
|
|
1154
|
-
return name;
|
|
1155
|
-
};
|
|
1156
|
-
return { context, helper };
|
|
1157
|
-
}
|
|
1158
|
-
function traverseNodes(nodes, transformer) {
|
|
1159
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
1160
|
-
traverseNode(nodes[i], transformer);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
function traverseNode(node, transformer) {
|
|
1164
|
-
// TODO: if we need pre-hook of transform, should be implemented to here
|
|
1165
|
-
switch (node.type) {
|
|
1166
|
-
case 1 /* NodeTypes.Plural */:
|
|
1167
|
-
traverseNodes(node.cases, transformer);
|
|
1168
|
-
transformer.helper("plural" /* HelperNameMap.PLURAL */);
|
|
1169
|
-
break;
|
|
1170
|
-
case 2 /* NodeTypes.Message */:
|
|
1171
|
-
traverseNodes(node.items, transformer);
|
|
1172
|
-
break;
|
|
1173
|
-
case 6 /* NodeTypes.Linked */: {
|
|
1174
|
-
const linked = node;
|
|
1175
|
-
traverseNode(linked.key, transformer);
|
|
1176
|
-
transformer.helper("linked" /* HelperNameMap.LINKED */);
|
|
1177
|
-
transformer.helper("type" /* HelperNameMap.TYPE */);
|
|
1178
|
-
break;
|
|
1179
|
-
}
|
|
1180
|
-
case 5 /* NodeTypes.List */:
|
|
1181
|
-
transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
|
|
1182
|
-
transformer.helper("list" /* HelperNameMap.LIST */);
|
|
1183
|
-
break;
|
|
1184
|
-
case 4 /* NodeTypes.Named */:
|
|
1185
|
-
transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
|
|
1186
|
-
transformer.helper("named" /* HelperNameMap.NAMED */);
|
|
1187
|
-
break;
|
|
1188
|
-
}
|
|
1189
|
-
// TODO: if we need post-hook of transform, should be implemented to here
|
|
1190
|
-
}
|
|
1191
|
-
// transform AST
|
|
1192
|
-
function transform(ast, options = {} // eslint-disable-line
|
|
1193
|
-
) {
|
|
1194
|
-
const transformer = createTransformer(ast);
|
|
1195
|
-
transformer.helper("normalize" /* HelperNameMap.NORMALIZE */);
|
|
1196
|
-
// traverse
|
|
1197
|
-
ast.body && traverseNode(ast.body, transformer);
|
|
1198
|
-
// set meta information
|
|
1199
|
-
const context = transformer.context();
|
|
1200
|
-
ast.helpers = Array.from(context.helpers);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
function optimize(ast) {
|
|
1204
|
-
const body = ast.body;
|
|
1205
|
-
if (body.type === 2 /* NodeTypes.Message */) {
|
|
1206
|
-
optimizeMessageNode(body);
|
|
1207
|
-
}
|
|
1208
|
-
else {
|
|
1209
|
-
body.cases.forEach(c => optimizeMessageNode(c));
|
|
1210
|
-
}
|
|
1211
|
-
return ast;
|
|
1212
|
-
}
|
|
1213
|
-
function optimizeMessageNode(message) {
|
|
1214
|
-
if (message.items.length === 1) {
|
|
1215
|
-
const item = message.items[0];
|
|
1216
|
-
if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
|
|
1217
|
-
message.static = item.value;
|
|
1218
|
-
delete item.value; // optimization for size
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
else {
|
|
1222
|
-
const values = [];
|
|
1223
|
-
for (let i = 0; i < message.items.length; i++) {
|
|
1224
|
-
const item = message.items[i];
|
|
1225
|
-
if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) {
|
|
1226
|
-
break;
|
|
1227
|
-
}
|
|
1228
|
-
if (item.value == null) {
|
|
1229
|
-
break;
|
|
1230
|
-
}
|
|
1231
|
-
values.push(item.value);
|
|
1232
|
-
}
|
|
1233
|
-
if (values.length === message.items.length) {
|
|
1234
|
-
message.static = join(values);
|
|
1235
|
-
for (let i = 0; i < message.items.length; i++) {
|
|
1236
|
-
const item = message.items[i];
|
|
1237
|
-
if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
|
|
1238
|
-
delete item.value; // optimization for size
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
const ERROR_DOMAIN$1 = 'minifier';
|
|
1246
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1247
|
-
function minify(node) {
|
|
1248
|
-
node.t = node.type;
|
|
1249
|
-
switch (node.type) {
|
|
1250
|
-
case 0 /* NodeTypes.Resource */: {
|
|
1251
|
-
const resource = node;
|
|
1252
|
-
minify(resource.body);
|
|
1253
|
-
resource.b = resource.body;
|
|
1254
|
-
delete resource.body;
|
|
1255
|
-
break;
|
|
1256
|
-
}
|
|
1257
|
-
case 1 /* NodeTypes.Plural */: {
|
|
1258
|
-
const plural = node;
|
|
1259
|
-
const cases = plural.cases;
|
|
1260
|
-
for (let i = 0; i < cases.length; i++) {
|
|
1261
|
-
minify(cases[i]);
|
|
1262
|
-
}
|
|
1263
|
-
plural.c = cases;
|
|
1264
|
-
delete plural.cases;
|
|
1265
|
-
break;
|
|
1266
|
-
}
|
|
1267
|
-
case 2 /* NodeTypes.Message */: {
|
|
1268
|
-
const message = node;
|
|
1269
|
-
const items = message.items;
|
|
1270
|
-
for (let i = 0; i < items.length; i++) {
|
|
1271
|
-
minify(items[i]);
|
|
1272
|
-
}
|
|
1273
|
-
message.i = items;
|
|
1274
|
-
delete message.items;
|
|
1275
|
-
if (message.static) {
|
|
1276
|
-
message.s = message.static;
|
|
1277
|
-
delete message.static;
|
|
1278
|
-
}
|
|
1279
|
-
break;
|
|
1280
|
-
}
|
|
1281
|
-
case 3 /* NodeTypes.Text */:
|
|
1282
|
-
case 9 /* NodeTypes.Literal */:
|
|
1283
|
-
case 8 /* NodeTypes.LinkedModifier */:
|
|
1284
|
-
case 7 /* NodeTypes.LinkedKey */: {
|
|
1285
|
-
const valueNode = node;
|
|
1286
|
-
if (valueNode.value) {
|
|
1287
|
-
valueNode.v = valueNode.value;
|
|
1288
|
-
delete valueNode.value;
|
|
1289
|
-
}
|
|
1290
|
-
break;
|
|
1291
|
-
}
|
|
1292
|
-
case 6 /* NodeTypes.Linked */: {
|
|
1293
|
-
const linked = node;
|
|
1294
|
-
minify(linked.key);
|
|
1295
|
-
linked.k = linked.key;
|
|
1296
|
-
delete linked.key;
|
|
1297
|
-
if (linked.modifier) {
|
|
1298
|
-
minify(linked.modifier);
|
|
1299
|
-
linked.m = linked.modifier;
|
|
1300
|
-
delete linked.modifier;
|
|
1301
|
-
}
|
|
1302
|
-
break;
|
|
1419
|
+
if (context.currentType === 13 /* TokenTypes.EOF */) {
|
|
1420
|
+
return msgNode;
|
|
1303
1421
|
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
list.i = list.index;
|
|
1307
|
-
delete list.index;
|
|
1308
|
-
break;
|
|
1422
|
+
else {
|
|
1423
|
+
return parsePlural(tokenizer, offset, startLoc, msgNode);
|
|
1309
1424
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1425
|
+
}
|
|
1426
|
+
function parse(source) {
|
|
1427
|
+
const tokenizer = createTokenizer(source, assign({}, options));
|
|
1428
|
+
const context = tokenizer.context();
|
|
1429
|
+
const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc);
|
|
1430
|
+
if (location && node.loc) {
|
|
1431
|
+
node.loc.source = source;
|
|
1315
1432
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1433
|
+
node.body = parseResource(tokenizer);
|
|
1434
|
+
if (options.onCacheKey) {
|
|
1435
|
+
node.cacheKey = options.onCacheKey(source);
|
|
1436
|
+
}
|
|
1437
|
+
// assert whether achieved to EOF
|
|
1438
|
+
if (context.currentType !== 13 /* TokenTypes.EOF */) {
|
|
1439
|
+
emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || '');
|
|
1440
|
+
}
|
|
1441
|
+
endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
|
|
1442
|
+
return node;
|
|
1323
1443
|
}
|
|
1324
|
-
|
|
1444
|
+
return { parse };
|
|
1445
|
+
}
|
|
1446
|
+
function getTokenCaption(token) {
|
|
1447
|
+
if (token.type === 13 /* TokenTypes.EOF */) {
|
|
1448
|
+
return 'EOF';
|
|
1449
|
+
}
|
|
1450
|
+
const name = (token.value || '').replace(/\r?\n/gu, '\\n');
|
|
1451
|
+
return name.length > 10 ? name.slice(0, 9) + '…' : name;
|
|
1325
1452
|
}
|
|
1326
|
-
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
1327
1453
|
|
|
1328
|
-
// eslint-disable-
|
|
1329
|
-
|
|
1330
|
-
const ERROR_DOMAIN = 'parser';
|
|
1331
|
-
function createCodeGenerator(ast, options) {
|
|
1332
|
-
const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options;
|
|
1333
|
-
const location = options.location !== false;
|
|
1454
|
+
function createTransformer(ast, options = {} // eslint-disable-line
|
|
1455
|
+
) {
|
|
1334
1456
|
const _context = {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
column: 1,
|
|
1338
|
-
line: 1,
|
|
1339
|
-
offset: 0,
|
|
1340
|
-
map: undefined,
|
|
1341
|
-
breakLineCode,
|
|
1342
|
-
needIndent: _needIndent,
|
|
1343
|
-
indentLevel: 0
|
|
1457
|
+
ast,
|
|
1458
|
+
helpers: new Set()
|
|
1344
1459
|
};
|
|
1345
|
-
if (location && ast.loc) {
|
|
1346
|
-
_context.source = ast.loc.source;
|
|
1347
|
-
}
|
|
1348
1460
|
const context = () => _context;
|
|
1349
|
-
|
|
1350
|
-
_context.
|
|
1351
|
-
|
|
1352
|
-
function _newline(n, withBreakLine = true) {
|
|
1353
|
-
const _breakLineCode = withBreakLine ? breakLineCode : '';
|
|
1354
|
-
push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
|
|
1355
|
-
}
|
|
1356
|
-
function indent(withNewLine = true) {
|
|
1357
|
-
const level = ++_context.indentLevel;
|
|
1358
|
-
withNewLine && _newline(level);
|
|
1359
|
-
}
|
|
1360
|
-
function deindent(withNewLine = true) {
|
|
1361
|
-
const level = --_context.indentLevel;
|
|
1362
|
-
withNewLine && _newline(level);
|
|
1363
|
-
}
|
|
1364
|
-
function newline() {
|
|
1365
|
-
_newline(_context.indentLevel);
|
|
1366
|
-
}
|
|
1367
|
-
const helper = (key) => `_${key}`;
|
|
1368
|
-
const needIndent = () => _context.needIndent;
|
|
1369
|
-
return {
|
|
1370
|
-
context,
|
|
1371
|
-
push,
|
|
1372
|
-
indent,
|
|
1373
|
-
deindent,
|
|
1374
|
-
newline,
|
|
1375
|
-
helper,
|
|
1376
|
-
needIndent
|
|
1461
|
+
const helper = (name) => {
|
|
1462
|
+
_context.helpers.add(name);
|
|
1463
|
+
return name;
|
|
1377
1464
|
};
|
|
1465
|
+
return { context, helper };
|
|
1378
1466
|
}
|
|
1379
|
-
function
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
generateNode(generator, node.key);
|
|
1383
|
-
if (node.modifier) {
|
|
1384
|
-
generator.push(`, `);
|
|
1385
|
-
generateNode(generator, node.modifier);
|
|
1386
|
-
generator.push(`, _type`);
|
|
1387
|
-
}
|
|
1388
|
-
else {
|
|
1389
|
-
generator.push(`, undefined, _type`);
|
|
1390
|
-
}
|
|
1391
|
-
generator.push(`)`);
|
|
1392
|
-
}
|
|
1393
|
-
function generateMessageNode(generator, node) {
|
|
1394
|
-
const { helper, needIndent } = generator;
|
|
1395
|
-
generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`);
|
|
1396
|
-
generator.indent(needIndent());
|
|
1397
|
-
const length = node.items.length;
|
|
1398
|
-
for (let i = 0; i < length; i++) {
|
|
1399
|
-
generateNode(generator, node.items[i]);
|
|
1400
|
-
if (i === length - 1) {
|
|
1401
|
-
break;
|
|
1402
|
-
}
|
|
1403
|
-
generator.push(', ');
|
|
1404
|
-
}
|
|
1405
|
-
generator.deindent(needIndent());
|
|
1406
|
-
generator.push('])');
|
|
1407
|
-
}
|
|
1408
|
-
function generatePluralNode(generator, node) {
|
|
1409
|
-
const { helper, needIndent } = generator;
|
|
1410
|
-
if (node.cases.length > 1) {
|
|
1411
|
-
generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`);
|
|
1412
|
-
generator.indent(needIndent());
|
|
1413
|
-
const length = node.cases.length;
|
|
1414
|
-
for (let i = 0; i < length; i++) {
|
|
1415
|
-
generateNode(generator, node.cases[i]);
|
|
1416
|
-
if (i === length - 1) {
|
|
1417
|
-
break;
|
|
1418
|
-
}
|
|
1419
|
-
generator.push(', ');
|
|
1420
|
-
}
|
|
1421
|
-
generator.deindent(needIndent());
|
|
1422
|
-
generator.push(`])`);
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
function generateResource(generator, node) {
|
|
1426
|
-
if (node.body) {
|
|
1427
|
-
generateNode(generator, node.body);
|
|
1428
|
-
}
|
|
1429
|
-
else {
|
|
1430
|
-
generator.push('null');
|
|
1467
|
+
function traverseNodes(nodes, transformer) {
|
|
1468
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1469
|
+
traverseNode(nodes[i], transformer);
|
|
1431
1470
|
}
|
|
1432
1471
|
}
|
|
1433
|
-
function
|
|
1434
|
-
|
|
1472
|
+
function traverseNode(node, transformer) {
|
|
1473
|
+
// TODO: if we need pre-hook of transform, should be implemented to here
|
|
1435
1474
|
switch (node.type) {
|
|
1436
|
-
case 0 /* NodeTypes.Resource */:
|
|
1437
|
-
generateResource(generator, node);
|
|
1438
|
-
break;
|
|
1439
1475
|
case 1 /* NodeTypes.Plural */:
|
|
1440
|
-
|
|
1476
|
+
traverseNodes(node.cases, transformer);
|
|
1477
|
+
transformer.helper("plural" /* HelperNameMap.PLURAL */);
|
|
1441
1478
|
break;
|
|
1442
1479
|
case 2 /* NodeTypes.Message */:
|
|
1443
|
-
|
|
1444
|
-
break;
|
|
1445
|
-
case 6 /* NodeTypes.Linked */:
|
|
1446
|
-
generateLinkedNode(generator, node);
|
|
1447
|
-
break;
|
|
1448
|
-
case 8 /* NodeTypes.LinkedModifier */:
|
|
1449
|
-
generator.push(JSON.stringify(node.value), node);
|
|
1480
|
+
traverseNodes(node.items, transformer);
|
|
1450
1481
|
break;
|
|
1451
|
-
case
|
|
1452
|
-
|
|
1482
|
+
case 6 /* NodeTypes.Linked */: {
|
|
1483
|
+
const linked = node;
|
|
1484
|
+
traverseNode(linked.key, transformer);
|
|
1485
|
+
transformer.helper("linked" /* HelperNameMap.LINKED */);
|
|
1486
|
+
transformer.helper("type" /* HelperNameMap.TYPE */);
|
|
1453
1487
|
break;
|
|
1488
|
+
}
|
|
1454
1489
|
case 5 /* NodeTypes.List */:
|
|
1455
|
-
|
|
1490
|
+
transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
|
|
1491
|
+
transformer.helper("list" /* HelperNameMap.LIST */);
|
|
1456
1492
|
break;
|
|
1457
1493
|
case 4 /* NodeTypes.Named */:
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
case 9 /* NodeTypes.Literal */:
|
|
1461
|
-
generator.push(JSON.stringify(node.value), node);
|
|
1462
|
-
break;
|
|
1463
|
-
case 3 /* NodeTypes.Text */:
|
|
1464
|
-
generator.push(JSON.stringify(node.value), node);
|
|
1494
|
+
transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
|
|
1495
|
+
transformer.helper("named" /* HelperNameMap.NAMED */);
|
|
1465
1496
|
break;
|
|
1466
|
-
default:
|
|
1467
|
-
{
|
|
1468
|
-
throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, {
|
|
1469
|
-
domain: ERROR_DOMAIN,
|
|
1470
|
-
args: [node.type]
|
|
1471
|
-
});
|
|
1472
|
-
}
|
|
1473
1497
|
}
|
|
1498
|
+
// TODO: if we need post-hook of transform, should be implemented to here
|
|
1499
|
+
}
|
|
1500
|
+
// transform AST
|
|
1501
|
+
function transform(ast, options = {} // eslint-disable-line
|
|
1502
|
+
) {
|
|
1503
|
+
const transformer = createTransformer(ast);
|
|
1504
|
+
transformer.helper("normalize" /* HelperNameMap.NORMALIZE */);
|
|
1505
|
+
// traverse
|
|
1506
|
+
ast.body && traverseNode(ast.body, transformer);
|
|
1507
|
+
// set meta information
|
|
1508
|
+
const context = transformer.context();
|
|
1509
|
+
ast.helpers = Array.from(context.helpers);
|
|
1474
1510
|
}
|
|
1475
|
-
// generate code from AST
|
|
1476
|
-
const generate = (ast, options = {}) => {
|
|
1477
|
-
const mode = isString(options.mode) ? options.mode : 'normal';
|
|
1478
|
-
const filename = isString(options.filename)
|
|
1479
|
-
? options.filename
|
|
1480
|
-
: 'message.intl';
|
|
1481
|
-
const sourceMap = !!options.sourceMap;
|
|
1482
|
-
// prettier-ignore
|
|
1483
|
-
const breakLineCode = options.breakLineCode != null
|
|
1484
|
-
? options.breakLineCode
|
|
1485
|
-
: mode === 'arrow'
|
|
1486
|
-
? ';'
|
|
1487
|
-
: '\n';
|
|
1488
|
-
const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
|
|
1489
|
-
const helpers = ast.helpers || [];
|
|
1490
|
-
const generator = createCodeGenerator(ast, {
|
|
1491
|
-
mode,
|
|
1492
|
-
filename,
|
|
1493
|
-
sourceMap,
|
|
1494
|
-
breakLineCode,
|
|
1495
|
-
needIndent
|
|
1496
|
-
});
|
|
1497
|
-
generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
|
|
1498
|
-
generator.indent(needIndent);
|
|
1499
|
-
if (helpers.length > 0) {
|
|
1500
|
-
generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`);
|
|
1501
|
-
generator.newline();
|
|
1502
|
-
}
|
|
1503
|
-
generator.push(`return `);
|
|
1504
|
-
generateNode(generator, ast);
|
|
1505
|
-
generator.deindent(needIndent);
|
|
1506
|
-
generator.push(`}`);
|
|
1507
|
-
delete ast.helpers;
|
|
1508
|
-
const { code, map } = generator.context();
|
|
1509
|
-
return {
|
|
1510
|
-
ast,
|
|
1511
|
-
code,
|
|
1512
|
-
map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
1513
|
-
};
|
|
1514
|
-
};
|
|
1515
1511
|
|
|
1516
1512
|
function baseCompile(source, options = {}) {
|
|
1517
1513
|
const assignedOptions = assign({}, options);
|
|
1518
1514
|
const jit = !!assignedOptions.jit;
|
|
1519
|
-
const
|
|
1520
|
-
const
|
|
1515
|
+
const enableMangle = !!assignedOptions.mangle;
|
|
1516
|
+
const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize;
|
|
1521
1517
|
// parse source codes
|
|
1522
1518
|
const parser = createParser(assignedOptions);
|
|
1523
1519
|
const ast = parser.parse(source);
|
|
1520
|
+
// TODO:
|
|
1521
|
+
// With the introduction of Jit compilation, code generation is no longer necessary. This function may no longer be needed since tree-shaking is not possible.
|
|
1524
1522
|
if (!jit) {
|
|
1525
1523
|
// transform ASTs
|
|
1526
1524
|
transform(ast, assignedOptions);
|
|
@@ -1529,12 +1527,16 @@ function baseCompile(source, options = {}) {
|
|
|
1529
1527
|
}
|
|
1530
1528
|
else {
|
|
1531
1529
|
// optimize ASTs
|
|
1532
|
-
|
|
1530
|
+
enableOptimize && optimize(ast);
|
|
1533
1531
|
// minimize ASTs
|
|
1534
|
-
|
|
1532
|
+
enableMangle && mangle(ast);
|
|
1535
1533
|
// In JIT mode, no ast transform, no code generation.
|
|
1536
1534
|
return { ast, code: '' };
|
|
1537
1535
|
}
|
|
1538
1536
|
}
|
|
1539
1537
|
|
|
1540
|
-
|
|
1538
|
+
// eslint-disable-next-line no-useless-escape
|
|
1539
|
+
const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/;
|
|
1540
|
+
const detectHtmlTag = (source) => RE_HTML_TAG.test(source);
|
|
1541
|
+
|
|
1542
|
+
export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, LOCATION_STUB, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize };
|