@intlify/message-compiler 9.3.0-beta.9 → 9.3.0

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.
@@ -1,1436 +1,1580 @@
1
1
  /*!
2
- * message-compiler v9.3.0-beta.9
3
- * (c) 2022 kazuya kawaguchi
2
+ * message-compiler v9.3.0
3
+ * (c) 2023 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
6
  'use strict';
7
7
 
8
- Object.defineProperty(exports, '__esModule', { value: true });
9
-
10
8
  var shared = require('@intlify/shared');
11
- var sourceMap = require('source-map');
9
+ var sourceMapJs = require('source-map-js');
12
10
 
13
- const CompileErrorCodes = {
14
- // tokenizer error codes
15
- EXPECTED_TOKEN: 1,
16
- INVALID_TOKEN_IN_PLACEHOLDER: 2,
17
- UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3,
18
- UNKNOWN_ESCAPE_SEQUENCE: 4,
19
- INVALID_UNICODE_ESCAPE_SEQUENCE: 5,
20
- UNBALANCED_CLOSING_BRACE: 6,
21
- UNTERMINATED_CLOSING_BRACE: 7,
22
- EMPTY_PLACEHOLDER: 8,
23
- NOT_ALLOW_NEST_PLACEHOLDER: 9,
24
- INVALID_LINKED_FORMAT: 10,
25
- // parser error codes
26
- MUST_HAVE_MESSAGES_IN_PLURAL: 11,
27
- UNEXPECTED_EMPTY_LINKED_MODIFIER: 12,
28
- UNEXPECTED_EMPTY_LINKED_KEY: 13,
29
- UNEXPECTED_LEXICAL_ANALYSIS: 14,
30
- // Special value for higher-order compilers to pick up the last code
31
- // to avoid collision of error codes. This should always be kept as the last
32
- // item.
33
- __EXTEND_POINT__: 15
34
- };
35
- /** @internal */
36
- const errorMessages = {
37
- // tokenizer error messages
38
- [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`,
39
- [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`,
40
- [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`,
41
- [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`,
42
- [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`,
43
- [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`,
44
- [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`,
45
- [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`,
46
- [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`,
47
- [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`,
48
- // parser error messages
49
- [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`,
50
- [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`,
51
- [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`,
52
- [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`
53
- };
54
- function createCompileError(code, loc, options = {}) {
55
- const { domain, messages, args } = options;
56
- const msg = code;
57
- const error = new SyntaxError(String(msg));
58
- error.code = code;
59
- if (loc) {
60
- error.location = loc;
61
- }
62
- error.domain = domain;
63
- return error;
64
- }
65
- /** @internal */
66
- function defaultOnError(error) {
67
- throw error;
11
+ const LOCATION_STUB = {
12
+ start: { line: 1, column: 1, offset: 0 },
13
+ end: { line: 1, column: 1, offset: 0 }
14
+ };
15
+ function createPosition(line, column, offset) {
16
+ return { line, column, offset };
17
+ }
18
+ function createLocation(start, end, source) {
19
+ const loc = { start, end };
20
+ if (source != null) {
21
+ loc.source = source;
22
+ }
23
+ return loc;
68
24
  }
69
25
 
70
- const LocationStub = {
71
- start: { line: 1, column: 1, offset: 0 },
72
- end: { line: 1, column: 1, offset: 0 }
73
- };
74
- function createPosition(line, column, offset) {
75
- return { line, column, offset };
76
- }
77
- function createLocation(start, end, source) {
78
- const loc = { start, end };
79
- if (source != null) {
80
- loc.source = source;
81
- }
82
- return loc;
26
+ const CompileErrorCodes = {
27
+ // tokenizer error codes
28
+ EXPECTED_TOKEN: 1,
29
+ INVALID_TOKEN_IN_PLACEHOLDER: 2,
30
+ UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3,
31
+ UNKNOWN_ESCAPE_SEQUENCE: 4,
32
+ INVALID_UNICODE_ESCAPE_SEQUENCE: 5,
33
+ UNBALANCED_CLOSING_BRACE: 6,
34
+ UNTERMINATED_CLOSING_BRACE: 7,
35
+ EMPTY_PLACEHOLDER: 8,
36
+ NOT_ALLOW_NEST_PLACEHOLDER: 9,
37
+ INVALID_LINKED_FORMAT: 10,
38
+ // parser error codes
39
+ MUST_HAVE_MESSAGES_IN_PLURAL: 11,
40
+ UNEXPECTED_EMPTY_LINKED_MODIFIER: 12,
41
+ UNEXPECTED_EMPTY_LINKED_KEY: 13,
42
+ UNEXPECTED_LEXICAL_ANALYSIS: 14,
43
+ // generator error codes
44
+ UNHANDLED_CODEGEN_NODE_TYPE: 15,
45
+ // minifier error codes
46
+ UNHANDLED_MINIFIER_NODE_TYPE: 16,
47
+ // Special value for higher-order compilers to pick up the last code
48
+ // to avoid collision of error codes. This should always be kept as the last
49
+ // item.
50
+ __EXTEND_POINT__: 17
51
+ };
52
+ /** @internal */
53
+ const errorMessages = {
54
+ // tokenizer error messages
55
+ [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`,
56
+ [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`,
57
+ [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`,
58
+ [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`,
59
+ [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`,
60
+ [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`,
61
+ [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`,
62
+ [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`,
63
+ [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`,
64
+ [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`,
65
+ // parser error messages
66
+ [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`,
67
+ [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`,
68
+ [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`,
69
+ [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`,
70
+ // generator error messages
71
+ [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`,
72
+ // minimizer error messages
73
+ [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'`
74
+ };
75
+ function createCompileError(code, loc, options = {}) {
76
+ const { domain, messages, args } = options;
77
+ const msg = code;
78
+ const error = new SyntaxError(String(msg));
79
+ error.code = code;
80
+ if (loc) {
81
+ error.location = loc;
82
+ }
83
+ error.domain = domain;
84
+ return error;
85
+ }
86
+ /** @internal */
87
+ function defaultOnError(error) {
88
+ throw error;
83
89
  }
84
90
 
85
- const CHAR_SP = ' ';
86
- const CHAR_CR = '\r';
87
- const CHAR_LF = '\n';
88
- const CHAR_LS = String.fromCharCode(0x2028);
89
- const CHAR_PS = String.fromCharCode(0x2029);
90
- function createScanner(str) {
91
- const _buf = str;
92
- let _index = 0;
93
- let _line = 1;
94
- let _column = 1;
95
- let _peekOffset = 0;
96
- const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF;
97
- const isLF = (index) => _buf[index] === CHAR_LF;
98
- const isPS = (index) => _buf[index] === CHAR_PS;
99
- const isLS = (index) => _buf[index] === CHAR_LS;
100
- const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index);
101
- const index = () => _index;
102
- const line = () => _line;
103
- const column = () => _column;
104
- const peekOffset = () => _peekOffset;
105
- const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset];
106
- const currentChar = () => charAt(_index);
107
- const currentPeek = () => charAt(_index + _peekOffset);
108
- function next() {
109
- _peekOffset = 0;
110
- if (isLineEnd(_index)) {
111
- _line++;
112
- _column = 0;
113
- }
114
- if (isCRLF(_index)) {
115
- _index++;
116
- }
117
- _index++;
118
- _column++;
119
- return _buf[_index];
120
- }
121
- function peek() {
122
- if (isCRLF(_index + _peekOffset)) {
123
- _peekOffset++;
124
- }
125
- _peekOffset++;
126
- return _buf[_index + _peekOffset];
127
- }
128
- function reset() {
129
- _index = 0;
130
- _line = 1;
131
- _column = 1;
132
- _peekOffset = 0;
133
- }
134
- function resetPeek(offset = 0) {
135
- _peekOffset = offset;
136
- }
137
- function skipToPeek() {
138
- const target = _index + _peekOffset;
139
- // eslint-disable-next-line no-unmodified-loop-condition
140
- while (target !== _index) {
141
- next();
142
- }
143
- _peekOffset = 0;
144
- }
145
- return {
146
- index,
147
- line,
148
- column,
149
- peekOffset,
150
- charAt,
151
- currentChar,
152
- currentPeek,
153
- next,
154
- peek,
155
- reset,
156
- resetPeek,
157
- skipToPeek
158
- };
91
+ const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/;
92
+ const detectHtmlTag = (source) => RE_HTML_TAG.test(source);
93
+
94
+ const CHAR_SP = ' ';
95
+ const CHAR_CR = '\r';
96
+ const CHAR_LF = '\n';
97
+ const CHAR_LS = String.fromCharCode(0x2028);
98
+ const CHAR_PS = String.fromCharCode(0x2029);
99
+ function createScanner(str) {
100
+ const _buf = str;
101
+ let _index = 0;
102
+ let _line = 1;
103
+ let _column = 1;
104
+ let _peekOffset = 0;
105
+ const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF;
106
+ const isLF = (index) => _buf[index] === CHAR_LF;
107
+ const isPS = (index) => _buf[index] === CHAR_PS;
108
+ const isLS = (index) => _buf[index] === CHAR_LS;
109
+ const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index);
110
+ const index = () => _index;
111
+ const line = () => _line;
112
+ const column = () => _column;
113
+ const peekOffset = () => _peekOffset;
114
+ const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset];
115
+ const currentChar = () => charAt(_index);
116
+ const currentPeek = () => charAt(_index + _peekOffset);
117
+ function next() {
118
+ _peekOffset = 0;
119
+ if (isLineEnd(_index)) {
120
+ _line++;
121
+ _column = 0;
122
+ }
123
+ if (isCRLF(_index)) {
124
+ _index++;
125
+ }
126
+ _index++;
127
+ _column++;
128
+ return _buf[_index];
129
+ }
130
+ function peek() {
131
+ if (isCRLF(_index + _peekOffset)) {
132
+ _peekOffset++;
133
+ }
134
+ _peekOffset++;
135
+ return _buf[_index + _peekOffset];
136
+ }
137
+ function reset() {
138
+ _index = 0;
139
+ _line = 1;
140
+ _column = 1;
141
+ _peekOffset = 0;
142
+ }
143
+ function resetPeek(offset = 0) {
144
+ _peekOffset = offset;
145
+ }
146
+ function skipToPeek() {
147
+ const target = _index + _peekOffset;
148
+ // eslint-disable-next-line no-unmodified-loop-condition
149
+ while (target !== _index) {
150
+ next();
151
+ }
152
+ _peekOffset = 0;
153
+ }
154
+ return {
155
+ index,
156
+ line,
157
+ column,
158
+ peekOffset,
159
+ charAt,
160
+ currentChar,
161
+ currentPeek,
162
+ next,
163
+ peek,
164
+ reset,
165
+ resetPeek,
166
+ skipToPeek
167
+ };
159
168
  }
160
169
 
161
- const EOF = undefined;
162
- const LITERAL_DELIMITER = "'";
163
- const ERROR_DOMAIN$1 = 'tokenizer';
164
- function createTokenizer(source, options = {}) {
165
- const location = options.location !== false;
166
- const _scnr = createScanner(source);
167
- const currentOffset = () => _scnr.index();
168
- const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index());
169
- const _initLoc = currentPosition();
170
- const _initOffset = currentOffset();
171
- const _context = {
172
- currentType: 14 /* EOF */,
173
- offset: _initOffset,
174
- startLoc: _initLoc,
175
- endLoc: _initLoc,
176
- lastType: 14 /* EOF */,
177
- lastOffset: _initOffset,
178
- lastStartLoc: _initLoc,
179
- lastEndLoc: _initLoc,
180
- braceNest: 0,
181
- inLinked: false,
182
- text: ''
183
- };
184
- const context = () => _context;
185
- const { onError } = options;
186
- function emitError(code, pos, offset, ...args) {
187
- const ctx = context();
188
- pos.column += offset;
189
- pos.offset += offset;
190
- if (onError) {
191
- const loc = createLocation(ctx.startLoc, pos);
192
- const err = createCompileError(code, loc, {
193
- domain: ERROR_DOMAIN$1,
194
- args
195
- });
196
- onError(err);
197
- }
198
- }
199
- function getToken(context, type, value) {
200
- context.endLoc = currentPosition();
201
- context.currentType = type;
202
- const token = { type };
203
- if (location) {
204
- token.loc = createLocation(context.startLoc, context.endLoc);
205
- }
206
- if (value != null) {
207
- token.value = value;
208
- }
209
- return token;
210
- }
211
- const getEndToken = (context) => getToken(context, 14 /* EOF */);
212
- function eat(scnr, ch) {
213
- if (scnr.currentChar() === ch) {
214
- scnr.next();
215
- return ch;
216
- }
217
- else {
218
- emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch);
219
- return '';
220
- }
221
- }
222
- function peekSpaces(scnr) {
223
- let buf = '';
224
- while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) {
225
- buf += scnr.currentPeek();
226
- scnr.peek();
227
- }
228
- return buf;
229
- }
230
- function skipSpaces(scnr) {
231
- const buf = peekSpaces(scnr);
232
- scnr.skipToPeek();
233
- return buf;
234
- }
235
- function isIdentifierStart(ch) {
236
- if (ch === EOF) {
237
- return false;
238
- }
239
- const cc = ch.charCodeAt(0);
240
- return ((cc >= 97 && cc <= 122) || // a-z
241
- (cc >= 65 && cc <= 90) || // A-Z
242
- cc === 95 // _
243
- );
244
- }
245
- function isNumberStart(ch) {
246
- if (ch === EOF) {
247
- return false;
248
- }
249
- const cc = ch.charCodeAt(0);
250
- return cc >= 48 && cc <= 57; // 0-9
251
- }
252
- function isNamedIdentifierStart(scnr, context) {
253
- const { currentType } = context;
254
- if (currentType !== 2 /* BraceLeft */) {
255
- return false;
256
- }
257
- peekSpaces(scnr);
258
- const ret = isIdentifierStart(scnr.currentPeek());
259
- scnr.resetPeek();
260
- return ret;
261
- }
262
- function isListIdentifierStart(scnr, context) {
263
- const { currentType } = context;
264
- if (currentType !== 2 /* BraceLeft */) {
265
- return false;
266
- }
267
- peekSpaces(scnr);
268
- const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek();
269
- const ret = isNumberStart(ch);
270
- scnr.resetPeek();
271
- return ret;
272
- }
273
- function isLiteralStart(scnr, context) {
274
- const { currentType } = context;
275
- if (currentType !== 2 /* BraceLeft */) {
276
- return false;
277
- }
278
- peekSpaces(scnr);
279
- const ret = scnr.currentPeek() === LITERAL_DELIMITER;
280
- scnr.resetPeek();
281
- return ret;
282
- }
283
- function isLinkedDotStart(scnr, context) {
284
- const { currentType } = context;
285
- if (currentType !== 8 /* LinkedAlias */) {
286
- return false;
287
- }
288
- peekSpaces(scnr);
289
- const ret = scnr.currentPeek() === "." /* LinkedDot */;
290
- scnr.resetPeek();
291
- return ret;
292
- }
293
- function isLinkedModifierStart(scnr, context) {
294
- const { currentType } = context;
295
- if (currentType !== 9 /* LinkedDot */) {
296
- return false;
297
- }
298
- peekSpaces(scnr);
299
- const ret = isIdentifierStart(scnr.currentPeek());
300
- scnr.resetPeek();
301
- return ret;
302
- }
303
- function isLinkedDelimiterStart(scnr, context) {
304
- const { currentType } = context;
305
- if (!(currentType === 8 /* LinkedAlias */ ||
306
- currentType === 12 /* LinkedModifier */)) {
307
- return false;
308
- }
309
- peekSpaces(scnr);
310
- const ret = scnr.currentPeek() === ":" /* LinkedDelimiter */;
311
- scnr.resetPeek();
312
- return ret;
313
- }
314
- function isLinkedReferStart(scnr, context) {
315
- const { currentType } = context;
316
- if (currentType !== 10 /* LinkedDelimiter */) {
317
- return false;
318
- }
319
- const fn = () => {
320
- const ch = scnr.currentPeek();
321
- if (ch === "{" /* BraceLeft */) {
322
- return isIdentifierStart(scnr.peek());
323
- }
324
- else if (ch === "@" /* LinkedAlias */ ||
325
- ch === "%" /* Modulo */ ||
326
- ch === "|" /* Pipe */ ||
327
- ch === ":" /* LinkedDelimiter */ ||
328
- ch === "." /* LinkedDot */ ||
329
- ch === CHAR_SP ||
330
- !ch) {
331
- return false;
332
- }
333
- else if (ch === CHAR_LF) {
334
- scnr.peek();
335
- return fn();
336
- }
337
- else {
338
- // other characters
339
- return isIdentifierStart(ch);
340
- }
341
- };
342
- const ret = fn();
343
- scnr.resetPeek();
344
- return ret;
345
- }
346
- function isPluralStart(scnr) {
347
- peekSpaces(scnr);
348
- const ret = scnr.currentPeek() === "|" /* Pipe */;
349
- scnr.resetPeek();
350
- return ret;
351
- }
352
- function detectModuloStart(scnr) {
353
- const spaces = peekSpaces(scnr);
354
- const ret = scnr.currentPeek() === "%" /* Modulo */ &&
355
- scnr.peek() === "{" /* BraceLeft */;
356
- scnr.resetPeek();
357
- return {
358
- isModulo: ret,
359
- hasSpace: spaces.length > 0
360
- };
361
- }
362
- function isTextStart(scnr, reset = true) {
363
- const fn = (hasSpace = false, prev = '', detectModulo = false) => {
364
- const ch = scnr.currentPeek();
365
- if (ch === "{" /* BraceLeft */) {
366
- return prev === "%" /* Modulo */ ? false : hasSpace;
367
- }
368
- else if (ch === "@" /* LinkedAlias */ || !ch) {
369
- return prev === "%" /* Modulo */ ? true : hasSpace;
370
- }
371
- else if (ch === "%" /* Modulo */) {
372
- scnr.peek();
373
- return fn(hasSpace, "%" /* Modulo */, true);
374
- }
375
- else if (ch === "|" /* Pipe */) {
376
- return prev === "%" /* Modulo */ || detectModulo
377
- ? true
378
- : !(prev === CHAR_SP || prev === CHAR_LF);
379
- }
380
- else if (ch === CHAR_SP) {
381
- scnr.peek();
382
- return fn(true, CHAR_SP, detectModulo);
383
- }
384
- else if (ch === CHAR_LF) {
385
- scnr.peek();
386
- return fn(true, CHAR_LF, detectModulo);
387
- }
388
- else {
389
- return true;
390
- }
391
- };
392
- const ret = fn();
393
- reset && scnr.resetPeek();
394
- return ret;
395
- }
396
- function takeChar(scnr, fn) {
397
- const ch = scnr.currentChar();
398
- if (ch === EOF) {
399
- return EOF;
400
- }
401
- if (fn(ch)) {
402
- scnr.next();
403
- return ch;
404
- }
405
- return null;
406
- }
407
- function takeIdentifierChar(scnr) {
408
- const closure = (ch) => {
409
- const cc = ch.charCodeAt(0);
410
- return ((cc >= 97 && cc <= 122) || // a-z
411
- (cc >= 65 && cc <= 90) || // A-Z
412
- (cc >= 48 && cc <= 57) || // 0-9
413
- cc === 95 || // _
414
- cc === 36 // $
415
- );
416
- };
417
- return takeChar(scnr, closure);
418
- }
419
- function takeDigit(scnr) {
420
- const closure = (ch) => {
421
- const cc = ch.charCodeAt(0);
422
- return cc >= 48 && cc <= 57; // 0-9
423
- };
424
- return takeChar(scnr, closure);
425
- }
426
- function takeHexDigit(scnr) {
427
- const closure = (ch) => {
428
- const cc = ch.charCodeAt(0);
429
- return ((cc >= 48 && cc <= 57) || // 0-9
430
- (cc >= 65 && cc <= 70) || // A-F
431
- (cc >= 97 && cc <= 102)); // a-f
432
- };
433
- return takeChar(scnr, closure);
434
- }
435
- function getDigits(scnr) {
436
- let ch = '';
437
- let num = '';
438
- while ((ch = takeDigit(scnr))) {
439
- num += ch;
440
- }
441
- return num;
442
- }
443
- function readModulo(scnr) {
444
- skipSpaces(scnr);
445
- const ch = scnr.currentChar();
446
- if (ch !== "%" /* Modulo */) {
447
- emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch);
448
- }
449
- scnr.next();
450
- return "%" /* Modulo */;
451
- }
452
- function readText(scnr) {
453
- let buf = '';
454
- while (true) {
455
- const ch = scnr.currentChar();
456
- if (ch === "{" /* BraceLeft */ ||
457
- ch === "}" /* BraceRight */ ||
458
- ch === "@" /* LinkedAlias */ ||
459
- ch === "|" /* Pipe */ ||
460
- !ch) {
461
- break;
462
- }
463
- else if (ch === "%" /* Modulo */) {
464
- if (isTextStart(scnr)) {
465
- buf += ch;
466
- scnr.next();
467
- }
468
- else {
469
- break;
470
- }
471
- }
472
- else if (ch === CHAR_SP || ch === CHAR_LF) {
473
- if (isTextStart(scnr)) {
474
- buf += ch;
475
- scnr.next();
476
- }
477
- else if (isPluralStart(scnr)) {
478
- break;
479
- }
480
- else {
481
- buf += ch;
482
- scnr.next();
483
- }
484
- }
485
- else {
486
- buf += ch;
487
- scnr.next();
488
- }
489
- }
490
- return buf;
491
- }
492
- function readNamedIdentifier(scnr) {
493
- skipSpaces(scnr);
494
- let ch = '';
495
- let name = '';
496
- while ((ch = takeIdentifierChar(scnr))) {
497
- name += ch;
498
- }
499
- if (scnr.currentChar() === EOF) {
500
- emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
501
- }
502
- return name;
503
- }
504
- function readListIdentifier(scnr) {
505
- skipSpaces(scnr);
506
- let value = '';
507
- if (scnr.currentChar() === '-') {
508
- scnr.next();
509
- value += `-${getDigits(scnr)}`;
510
- }
511
- else {
512
- value += getDigits(scnr);
513
- }
514
- if (scnr.currentChar() === EOF) {
515
- emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
516
- }
517
- return value;
518
- }
519
- function readLiteral(scnr) {
520
- skipSpaces(scnr);
521
- eat(scnr, `\'`);
522
- let ch = '';
523
- let literal = '';
524
- const fn = (x) => x !== LITERAL_DELIMITER && x !== CHAR_LF;
525
- while ((ch = takeChar(scnr, fn))) {
526
- if (ch === '\\') {
527
- literal += readEscapeSequence(scnr);
528
- }
529
- else {
530
- literal += ch;
531
- }
532
- }
533
- const current = scnr.currentChar();
534
- if (current === CHAR_LF || current === EOF) {
535
- emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0);
536
- // TODO: Is it correct really?
537
- if (current === CHAR_LF) {
538
- scnr.next();
539
- eat(scnr, `\'`);
540
- }
541
- return literal;
542
- }
543
- eat(scnr, `\'`);
544
- return literal;
545
- }
546
- function readEscapeSequence(scnr) {
547
- const ch = scnr.currentChar();
548
- switch (ch) {
549
- case '\\':
550
- case `\'`:
551
- scnr.next();
552
- return `\\${ch}`;
553
- case 'u':
554
- return readUnicodeEscapeSequence(scnr, ch, 4);
555
- case 'U':
556
- return readUnicodeEscapeSequence(scnr, ch, 6);
557
- default:
558
- emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch);
559
- return '';
560
- }
561
- }
562
- function readUnicodeEscapeSequence(scnr, unicode, digits) {
563
- eat(scnr, unicode);
564
- let sequence = '';
565
- for (let i = 0; i < digits; i++) {
566
- const ch = takeHexDigit(scnr);
567
- if (!ch) {
568
- emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`);
569
- break;
570
- }
571
- sequence += ch;
572
- }
573
- return `\\${unicode}${sequence}`;
574
- }
575
- function readInvalidIdentifier(scnr) {
576
- skipSpaces(scnr);
577
- let ch = '';
578
- let identifiers = '';
579
- const closure = (ch) => ch !== "{" /* BraceLeft */ &&
580
- ch !== "}" /* BraceRight */ &&
581
- ch !== CHAR_SP &&
582
- ch !== CHAR_LF;
583
- while ((ch = takeChar(scnr, closure))) {
584
- identifiers += ch;
585
- }
586
- return identifiers;
587
- }
588
- function readLinkedModifier(scnr) {
589
- let ch = '';
590
- let name = '';
591
- while ((ch = takeIdentifierChar(scnr))) {
592
- name += ch;
593
- }
594
- return name;
595
- }
596
- function readLinkedRefer(scnr) {
597
- const fn = (detect = false, buf) => {
598
- const ch = scnr.currentChar();
599
- if (ch === "{" /* BraceLeft */ ||
600
- ch === "%" /* Modulo */ ||
601
- ch === "@" /* LinkedAlias */ ||
602
- ch === "|" /* Pipe */ ||
603
- !ch) {
604
- return buf;
605
- }
606
- else if (ch === CHAR_SP) {
607
- return buf;
608
- }
609
- else if (ch === CHAR_LF) {
610
- buf += ch;
611
- scnr.next();
612
- return fn(detect, buf);
613
- }
614
- else {
615
- buf += ch;
616
- scnr.next();
617
- return fn(true, buf);
618
- }
619
- };
620
- return fn(false, '');
621
- }
622
- function readPlural(scnr) {
623
- skipSpaces(scnr);
624
- const plural = eat(scnr, "|" /* Pipe */);
625
- skipSpaces(scnr);
626
- return plural;
627
- }
628
- // TODO: We need refactoring of token parsing ...
629
- function readTokenInPlaceholder(scnr, context) {
630
- let token = null;
631
- const ch = scnr.currentChar();
632
- switch (ch) {
633
- case "{" /* BraceLeft */:
634
- if (context.braceNest >= 1) {
635
- emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0);
636
- }
637
- scnr.next();
638
- token = getToken(context, 2 /* BraceLeft */, "{" /* BraceLeft */);
639
- skipSpaces(scnr);
640
- context.braceNest++;
641
- return token;
642
- case "}" /* BraceRight */:
643
- if (context.braceNest > 0 &&
644
- context.currentType === 2 /* BraceLeft */) {
645
- emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0);
646
- }
647
- scnr.next();
648
- token = getToken(context, 3 /* BraceRight */, "}" /* BraceRight */);
649
- context.braceNest--;
650
- context.braceNest > 0 && skipSpaces(scnr);
651
- if (context.inLinked && context.braceNest === 0) {
652
- context.inLinked = false;
653
- }
654
- return token;
655
- case "@" /* LinkedAlias */:
656
- if (context.braceNest > 0) {
657
- emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
658
- }
659
- token = readTokenInLinked(scnr, context) || getEndToken(context);
660
- context.braceNest = 0;
661
- return token;
662
- default:
663
- let validNamedIdentifier = true;
664
- let validListIdentifier = true;
665
- let validLiteral = true;
666
- if (isPluralStart(scnr)) {
667
- if (context.braceNest > 0) {
668
- emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
669
- }
670
- token = getToken(context, 1 /* Pipe */, readPlural(scnr));
671
- // reset
672
- context.braceNest = 0;
673
- context.inLinked = false;
674
- return token;
675
- }
676
- if (context.braceNest > 0 &&
677
- (context.currentType === 5 /* Named */ ||
678
- context.currentType === 6 /* List */ ||
679
- context.currentType === 7 /* Literal */)) {
680
- emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
681
- context.braceNest = 0;
682
- return readToken(scnr, context);
683
- }
684
- if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) {
685
- token = getToken(context, 5 /* Named */, readNamedIdentifier(scnr));
686
- skipSpaces(scnr);
687
- return token;
688
- }
689
- if ((validListIdentifier = isListIdentifierStart(scnr, context))) {
690
- token = getToken(context, 6 /* List */, readListIdentifier(scnr));
691
- skipSpaces(scnr);
692
- return token;
693
- }
694
- if ((validLiteral = isLiteralStart(scnr, context))) {
695
- token = getToken(context, 7 /* Literal */, readLiteral(scnr));
696
- skipSpaces(scnr);
697
- return token;
698
- }
699
- if (!validNamedIdentifier && !validListIdentifier && !validLiteral) {
700
- // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ...
701
- token = getToken(context, 13 /* InvalidPlace */, readInvalidIdentifier(scnr));
702
- emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value);
703
- skipSpaces(scnr);
704
- return token;
705
- }
706
- break;
707
- }
708
- return token;
709
- }
710
- // TODO: We need refactoring of token parsing ...
711
- function readTokenInLinked(scnr, context) {
712
- const { currentType } = context;
713
- let token = null;
714
- const ch = scnr.currentChar();
715
- if ((currentType === 8 /* LinkedAlias */ ||
716
- currentType === 9 /* LinkedDot */ ||
717
- currentType === 12 /* LinkedModifier */ ||
718
- currentType === 10 /* LinkedDelimiter */) &&
719
- (ch === CHAR_LF || ch === CHAR_SP)) {
720
- emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0);
721
- }
722
- switch (ch) {
723
- case "@" /* LinkedAlias */:
724
- scnr.next();
725
- token = getToken(context, 8 /* LinkedAlias */, "@" /* LinkedAlias */);
726
- context.inLinked = true;
727
- return token;
728
- case "." /* LinkedDot */:
729
- skipSpaces(scnr);
730
- scnr.next();
731
- return getToken(context, 9 /* LinkedDot */, "." /* LinkedDot */);
732
- case ":" /* LinkedDelimiter */:
733
- skipSpaces(scnr);
734
- scnr.next();
735
- return getToken(context, 10 /* LinkedDelimiter */, ":" /* LinkedDelimiter */);
736
- default:
737
- if (isPluralStart(scnr)) {
738
- token = getToken(context, 1 /* Pipe */, readPlural(scnr));
739
- // reset
740
- context.braceNest = 0;
741
- context.inLinked = false;
742
- return token;
743
- }
744
- if (isLinkedDotStart(scnr, context) ||
745
- isLinkedDelimiterStart(scnr, context)) {
746
- skipSpaces(scnr);
747
- return readTokenInLinked(scnr, context);
748
- }
749
- if (isLinkedModifierStart(scnr, context)) {
750
- skipSpaces(scnr);
751
- return getToken(context, 12 /* LinkedModifier */, readLinkedModifier(scnr));
752
- }
753
- if (isLinkedReferStart(scnr, context)) {
754
- skipSpaces(scnr);
755
- if (ch === "{" /* BraceLeft */) {
756
- // scan the placeholder
757
- return readTokenInPlaceholder(scnr, context) || token;
758
- }
759
- else {
760
- return getToken(context, 11 /* LinkedKey */, readLinkedRefer(scnr));
761
- }
762
- }
763
- if (currentType === 8 /* LinkedAlias */) {
764
- emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0);
765
- }
766
- context.braceNest = 0;
767
- context.inLinked = false;
768
- return readToken(scnr, context);
769
- }
770
- }
771
- // TODO: We need refactoring of token parsing ...
772
- function readToken(scnr, context) {
773
- let token = { type: 14 /* EOF */ };
774
- if (context.braceNest > 0) {
775
- return readTokenInPlaceholder(scnr, context) || getEndToken(context);
776
- }
777
- if (context.inLinked) {
778
- return readTokenInLinked(scnr, context) || getEndToken(context);
779
- }
780
- const ch = scnr.currentChar();
781
- switch (ch) {
782
- case "{" /* BraceLeft */:
783
- return readTokenInPlaceholder(scnr, context) || getEndToken(context);
784
- case "}" /* BraceRight */:
785
- emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0);
786
- scnr.next();
787
- return getToken(context, 3 /* BraceRight */, "}" /* BraceRight */);
788
- case "@" /* LinkedAlias */:
789
- return readTokenInLinked(scnr, context) || getEndToken(context);
790
- default:
791
- if (isPluralStart(scnr)) {
792
- token = getToken(context, 1 /* Pipe */, readPlural(scnr));
793
- // reset
794
- context.braceNest = 0;
795
- context.inLinked = false;
796
- return token;
797
- }
798
- const { isModulo, hasSpace } = detectModuloStart(scnr);
799
- if (isModulo) {
800
- return hasSpace
801
- ? getToken(context, 0 /* Text */, readText(scnr))
802
- : getToken(context, 4 /* Modulo */, readModulo(scnr));
803
- }
804
- if (isTextStart(scnr)) {
805
- return getToken(context, 0 /* Text */, readText(scnr));
806
- }
807
- break;
808
- }
809
- return token;
810
- }
811
- function nextToken() {
812
- const { currentType, offset, startLoc, endLoc } = _context;
813
- _context.lastType = currentType;
814
- _context.lastOffset = offset;
815
- _context.lastStartLoc = startLoc;
816
- _context.lastEndLoc = endLoc;
817
- _context.offset = currentOffset();
818
- _context.startLoc = currentPosition();
819
- if (_scnr.currentChar() === EOF) {
820
- return getToken(_context, 14 /* EOF */);
821
- }
822
- return readToken(_scnr, _context);
823
- }
824
- return {
825
- nextToken,
826
- currentOffset,
827
- currentPosition,
828
- context
829
- };
170
+ const EOF = undefined;
171
+ const DOT = '.';
172
+ const LITERAL_DELIMITER = "'";
173
+ const ERROR_DOMAIN$1 = 'tokenizer';
174
+ function createTokenizer(source, options = {}) {
175
+ const location = options.location !== false;
176
+ const _scnr = createScanner(source);
177
+ const currentOffset = () => _scnr.index();
178
+ const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index());
179
+ const _initLoc = currentPosition();
180
+ const _initOffset = currentOffset();
181
+ const _context = {
182
+ currentType: 14 /* TokenTypes.EOF */,
183
+ offset: _initOffset,
184
+ startLoc: _initLoc,
185
+ endLoc: _initLoc,
186
+ lastType: 14 /* TokenTypes.EOF */,
187
+ lastOffset: _initOffset,
188
+ lastStartLoc: _initLoc,
189
+ lastEndLoc: _initLoc,
190
+ braceNest: 0,
191
+ inLinked: false,
192
+ text: ''
193
+ };
194
+ const context = () => _context;
195
+ const { onError } = options;
196
+ function emitError(code, pos, offset, ...args) {
197
+ const ctx = context();
198
+ pos.column += offset;
199
+ pos.offset += offset;
200
+ if (onError) {
201
+ const loc = location ? createLocation(ctx.startLoc, pos) : null;
202
+ const err = createCompileError(code, loc, {
203
+ domain: ERROR_DOMAIN$1,
204
+ args
205
+ });
206
+ onError(err);
207
+ }
208
+ }
209
+ function getToken(context, type, value) {
210
+ context.endLoc = currentPosition();
211
+ context.currentType = type;
212
+ const token = { type };
213
+ if (location) {
214
+ token.loc = createLocation(context.startLoc, context.endLoc);
215
+ }
216
+ if (value != null) {
217
+ token.value = value;
218
+ }
219
+ return token;
220
+ }
221
+ const getEndToken = (context) => getToken(context, 14 /* TokenTypes.EOF */);
222
+ function eat(scnr, ch) {
223
+ if (scnr.currentChar() === ch) {
224
+ scnr.next();
225
+ return ch;
226
+ }
227
+ else {
228
+ emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch);
229
+ return '';
230
+ }
231
+ }
232
+ function peekSpaces(scnr) {
233
+ let buf = '';
234
+ while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) {
235
+ buf += scnr.currentPeek();
236
+ scnr.peek();
237
+ }
238
+ return buf;
239
+ }
240
+ function skipSpaces(scnr) {
241
+ const buf = peekSpaces(scnr);
242
+ scnr.skipToPeek();
243
+ return buf;
244
+ }
245
+ function isIdentifierStart(ch) {
246
+ if (ch === EOF) {
247
+ return false;
248
+ }
249
+ const cc = ch.charCodeAt(0);
250
+ return ((cc >= 97 && cc <= 122) || // a-z
251
+ (cc >= 65 && cc <= 90) || // A-Z
252
+ cc === 95 // _
253
+ );
254
+ }
255
+ function isNumberStart(ch) {
256
+ if (ch === EOF) {
257
+ return false;
258
+ }
259
+ const cc = ch.charCodeAt(0);
260
+ return cc >= 48 && cc <= 57; // 0-9
261
+ }
262
+ function isNamedIdentifierStart(scnr, context) {
263
+ const { currentType } = context;
264
+ if (currentType !== 2 /* TokenTypes.BraceLeft */) {
265
+ return false;
266
+ }
267
+ peekSpaces(scnr);
268
+ const ret = isIdentifierStart(scnr.currentPeek());
269
+ scnr.resetPeek();
270
+ return ret;
271
+ }
272
+ function isListIdentifierStart(scnr, context) {
273
+ const { currentType } = context;
274
+ if (currentType !== 2 /* TokenTypes.BraceLeft */) {
275
+ return false;
276
+ }
277
+ peekSpaces(scnr);
278
+ const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek();
279
+ const ret = isNumberStart(ch);
280
+ scnr.resetPeek();
281
+ return ret;
282
+ }
283
+ function isLiteralStart(scnr, context) {
284
+ const { currentType } = context;
285
+ if (currentType !== 2 /* TokenTypes.BraceLeft */) {
286
+ return false;
287
+ }
288
+ peekSpaces(scnr);
289
+ const ret = scnr.currentPeek() === LITERAL_DELIMITER;
290
+ scnr.resetPeek();
291
+ return ret;
292
+ }
293
+ function isLinkedDotStart(scnr, context) {
294
+ const { currentType } = context;
295
+ if (currentType !== 8 /* TokenTypes.LinkedAlias */) {
296
+ return false;
297
+ }
298
+ peekSpaces(scnr);
299
+ const ret = scnr.currentPeek() === "." /* TokenChars.LinkedDot */;
300
+ scnr.resetPeek();
301
+ return ret;
302
+ }
303
+ function isLinkedModifierStart(scnr, context) {
304
+ const { currentType } = context;
305
+ if (currentType !== 9 /* TokenTypes.LinkedDot */) {
306
+ return false;
307
+ }
308
+ peekSpaces(scnr);
309
+ const ret = isIdentifierStart(scnr.currentPeek());
310
+ scnr.resetPeek();
311
+ return ret;
312
+ }
313
+ function isLinkedDelimiterStart(scnr, context) {
314
+ const { currentType } = context;
315
+ if (!(currentType === 8 /* TokenTypes.LinkedAlias */ ||
316
+ currentType === 12 /* TokenTypes.LinkedModifier */)) {
317
+ return false;
318
+ }
319
+ peekSpaces(scnr);
320
+ const ret = scnr.currentPeek() === ":" /* TokenChars.LinkedDelimiter */;
321
+ scnr.resetPeek();
322
+ return ret;
323
+ }
324
+ function isLinkedReferStart(scnr, context) {
325
+ const { currentType } = context;
326
+ if (currentType !== 10 /* TokenTypes.LinkedDelimiter */) {
327
+ return false;
328
+ }
329
+ const fn = () => {
330
+ const ch = scnr.currentPeek();
331
+ if (ch === "{" /* TokenChars.BraceLeft */) {
332
+ return isIdentifierStart(scnr.peek());
333
+ }
334
+ else if (ch === "@" /* TokenChars.LinkedAlias */ ||
335
+ ch === "%" /* TokenChars.Modulo */ ||
336
+ ch === "|" /* TokenChars.Pipe */ ||
337
+ ch === ":" /* TokenChars.LinkedDelimiter */ ||
338
+ ch === "." /* TokenChars.LinkedDot */ ||
339
+ ch === CHAR_SP ||
340
+ !ch) {
341
+ return false;
342
+ }
343
+ else if (ch === CHAR_LF) {
344
+ scnr.peek();
345
+ return fn();
346
+ }
347
+ else {
348
+ // other characters
349
+ return isIdentifierStart(ch);
350
+ }
351
+ };
352
+ const ret = fn();
353
+ scnr.resetPeek();
354
+ return ret;
355
+ }
356
+ function isPluralStart(scnr) {
357
+ peekSpaces(scnr);
358
+ const ret = scnr.currentPeek() === "|" /* TokenChars.Pipe */;
359
+ scnr.resetPeek();
360
+ return ret;
361
+ }
362
+ function detectModuloStart(scnr) {
363
+ const spaces = peekSpaces(scnr);
364
+ const ret = scnr.currentPeek() === "%" /* TokenChars.Modulo */ &&
365
+ scnr.peek() === "{" /* TokenChars.BraceLeft */;
366
+ scnr.resetPeek();
367
+ return {
368
+ isModulo: ret,
369
+ hasSpace: spaces.length > 0
370
+ };
371
+ }
372
+ function isTextStart(scnr, reset = true) {
373
+ const fn = (hasSpace = false, prev = '', detectModulo = false) => {
374
+ const ch = scnr.currentPeek();
375
+ if (ch === "{" /* TokenChars.BraceLeft */) {
376
+ return prev === "%" /* TokenChars.Modulo */ ? false : hasSpace;
377
+ }
378
+ else if (ch === "@" /* TokenChars.LinkedAlias */ || !ch) {
379
+ return prev === "%" /* TokenChars.Modulo */ ? true : hasSpace;
380
+ }
381
+ else if (ch === "%" /* TokenChars.Modulo */) {
382
+ scnr.peek();
383
+ return fn(hasSpace, "%" /* TokenChars.Modulo */, true);
384
+ }
385
+ else if (ch === "|" /* TokenChars.Pipe */) {
386
+ return prev === "%" /* TokenChars.Modulo */ || detectModulo
387
+ ? true
388
+ : !(prev === CHAR_SP || prev === CHAR_LF);
389
+ }
390
+ else if (ch === CHAR_SP) {
391
+ scnr.peek();
392
+ return fn(true, CHAR_SP, detectModulo);
393
+ }
394
+ else if (ch === CHAR_LF) {
395
+ scnr.peek();
396
+ return fn(true, CHAR_LF, detectModulo);
397
+ }
398
+ else {
399
+ return true;
400
+ }
401
+ };
402
+ const ret = fn();
403
+ reset && scnr.resetPeek();
404
+ return ret;
405
+ }
406
+ function takeChar(scnr, fn) {
407
+ const ch = scnr.currentChar();
408
+ if (ch === EOF) {
409
+ return EOF;
410
+ }
411
+ if (fn(ch)) {
412
+ scnr.next();
413
+ return ch;
414
+ }
415
+ return null;
416
+ }
417
+ function takeIdentifierChar(scnr) {
418
+ const closure = (ch) => {
419
+ const cc = ch.charCodeAt(0);
420
+ return ((cc >= 97 && cc <= 122) || // a-z
421
+ (cc >= 65 && cc <= 90) || // A-Z
422
+ (cc >= 48 && cc <= 57) || // 0-9
423
+ cc === 95 || // _
424
+ cc === 36 // $
425
+ );
426
+ };
427
+ return takeChar(scnr, closure);
428
+ }
429
+ function takeDigit(scnr) {
430
+ const closure = (ch) => {
431
+ const cc = ch.charCodeAt(0);
432
+ return cc >= 48 && cc <= 57; // 0-9
433
+ };
434
+ return takeChar(scnr, closure);
435
+ }
436
+ function takeHexDigit(scnr) {
437
+ const closure = (ch) => {
438
+ const cc = ch.charCodeAt(0);
439
+ return ((cc >= 48 && cc <= 57) || // 0-9
440
+ (cc >= 65 && cc <= 70) || // A-F
441
+ (cc >= 97 && cc <= 102)); // a-f
442
+ };
443
+ return takeChar(scnr, closure);
444
+ }
445
+ function getDigits(scnr) {
446
+ let ch = '';
447
+ let num = '';
448
+ while ((ch = takeDigit(scnr))) {
449
+ num += ch;
450
+ }
451
+ return num;
452
+ }
453
+ function readModulo(scnr) {
454
+ skipSpaces(scnr);
455
+ const ch = scnr.currentChar();
456
+ if (ch !== "%" /* TokenChars.Modulo */) {
457
+ emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch);
458
+ }
459
+ scnr.next();
460
+ return "%" /* TokenChars.Modulo */;
461
+ }
462
+ function readText(scnr) {
463
+ let buf = '';
464
+ while (true) {
465
+ const ch = scnr.currentChar();
466
+ if (ch === "{" /* TokenChars.BraceLeft */ ||
467
+ ch === "}" /* TokenChars.BraceRight */ ||
468
+ ch === "@" /* TokenChars.LinkedAlias */ ||
469
+ ch === "|" /* TokenChars.Pipe */ ||
470
+ !ch) {
471
+ break;
472
+ }
473
+ else if (ch === "%" /* TokenChars.Modulo */) {
474
+ if (isTextStart(scnr)) {
475
+ buf += ch;
476
+ scnr.next();
477
+ }
478
+ else {
479
+ break;
480
+ }
481
+ }
482
+ else if (ch === CHAR_SP || ch === CHAR_LF) {
483
+ if (isTextStart(scnr)) {
484
+ buf += ch;
485
+ scnr.next();
486
+ }
487
+ else if (isPluralStart(scnr)) {
488
+ break;
489
+ }
490
+ else {
491
+ buf += ch;
492
+ scnr.next();
493
+ }
494
+ }
495
+ else {
496
+ buf += ch;
497
+ scnr.next();
498
+ }
499
+ }
500
+ return buf;
501
+ }
502
+ function readNamedIdentifier(scnr) {
503
+ skipSpaces(scnr);
504
+ let ch = '';
505
+ let name = '';
506
+ while ((ch = takeIdentifierChar(scnr))) {
507
+ name += ch;
508
+ }
509
+ if (scnr.currentChar() === EOF) {
510
+ emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
511
+ }
512
+ return name;
513
+ }
514
+ function readListIdentifier(scnr) {
515
+ skipSpaces(scnr);
516
+ let value = '';
517
+ if (scnr.currentChar() === '-') {
518
+ scnr.next();
519
+ value += `-${getDigits(scnr)}`;
520
+ }
521
+ else {
522
+ value += getDigits(scnr);
523
+ }
524
+ if (scnr.currentChar() === EOF) {
525
+ emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
526
+ }
527
+ return value;
528
+ }
529
+ function readLiteral(scnr) {
530
+ skipSpaces(scnr);
531
+ eat(scnr, `\'`);
532
+ let ch = '';
533
+ let literal = '';
534
+ const fn = (x) => x !== LITERAL_DELIMITER && x !== CHAR_LF;
535
+ while ((ch = takeChar(scnr, fn))) {
536
+ if (ch === '\\') {
537
+ literal += readEscapeSequence(scnr);
538
+ }
539
+ else {
540
+ literal += ch;
541
+ }
542
+ }
543
+ const current = scnr.currentChar();
544
+ if (current === CHAR_LF || current === EOF) {
545
+ emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0);
546
+ // TODO: Is it correct really?
547
+ if (current === CHAR_LF) {
548
+ scnr.next();
549
+ eat(scnr, `\'`);
550
+ }
551
+ return literal;
552
+ }
553
+ eat(scnr, `\'`);
554
+ return literal;
555
+ }
556
+ function readEscapeSequence(scnr) {
557
+ const ch = scnr.currentChar();
558
+ switch (ch) {
559
+ case '\\':
560
+ case `\'`:
561
+ scnr.next();
562
+ return `\\${ch}`;
563
+ case 'u':
564
+ return readUnicodeEscapeSequence(scnr, ch, 4);
565
+ case 'U':
566
+ return readUnicodeEscapeSequence(scnr, ch, 6);
567
+ default:
568
+ emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch);
569
+ return '';
570
+ }
571
+ }
572
+ function readUnicodeEscapeSequence(scnr, unicode, digits) {
573
+ eat(scnr, unicode);
574
+ let sequence = '';
575
+ for (let i = 0; i < digits; i++) {
576
+ const ch = takeHexDigit(scnr);
577
+ if (!ch) {
578
+ emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`);
579
+ break;
580
+ }
581
+ sequence += ch;
582
+ }
583
+ return `\\${unicode}${sequence}`;
584
+ }
585
+ function readInvalidIdentifier(scnr) {
586
+ skipSpaces(scnr);
587
+ let ch = '';
588
+ let identifiers = '';
589
+ const closure = (ch) => ch !== "{" /* TokenChars.BraceLeft */ &&
590
+ ch !== "}" /* TokenChars.BraceRight */ &&
591
+ ch !== CHAR_SP &&
592
+ ch !== CHAR_LF;
593
+ while ((ch = takeChar(scnr, closure))) {
594
+ identifiers += ch;
595
+ }
596
+ return identifiers;
597
+ }
598
+ function readLinkedModifier(scnr) {
599
+ let ch = '';
600
+ let name = '';
601
+ while ((ch = takeIdentifierChar(scnr))) {
602
+ name += ch;
603
+ }
604
+ return name;
605
+ }
606
+ function readLinkedRefer(scnr) {
607
+ const fn = (detect = false, buf) => {
608
+ const ch = scnr.currentChar();
609
+ if (ch === "{" /* TokenChars.BraceLeft */ ||
610
+ ch === "%" /* TokenChars.Modulo */ ||
611
+ ch === "@" /* TokenChars.LinkedAlias */ ||
612
+ ch === "|" /* TokenChars.Pipe */ ||
613
+ !ch) {
614
+ return buf;
615
+ }
616
+ else if (ch === CHAR_SP) {
617
+ return buf;
618
+ }
619
+ else if (ch === CHAR_LF || ch === DOT) {
620
+ buf += ch;
621
+ scnr.next();
622
+ return fn(detect, buf);
623
+ }
624
+ else if (!isIdentifierStart(ch)) {
625
+ return buf;
626
+ }
627
+ else {
628
+ buf += ch;
629
+ scnr.next();
630
+ return fn(true, buf);
631
+ }
632
+ };
633
+ return fn(false, '');
634
+ }
635
+ function readPlural(scnr) {
636
+ skipSpaces(scnr);
637
+ const plural = eat(scnr, "|" /* TokenChars.Pipe */);
638
+ skipSpaces(scnr);
639
+ return plural;
640
+ }
641
+ // TODO: We need refactoring of token parsing ...
642
+ function readTokenInPlaceholder(scnr, context) {
643
+ let token = null;
644
+ const ch = scnr.currentChar();
645
+ switch (ch) {
646
+ case "{" /* TokenChars.BraceLeft */:
647
+ if (context.braceNest >= 1) {
648
+ emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0);
649
+ }
650
+ scnr.next();
651
+ token = getToken(context, 2 /* TokenTypes.BraceLeft */, "{" /* TokenChars.BraceLeft */);
652
+ skipSpaces(scnr);
653
+ context.braceNest++;
654
+ return token;
655
+ case "}" /* TokenChars.BraceRight */:
656
+ if (context.braceNest > 0 &&
657
+ context.currentType === 2 /* TokenTypes.BraceLeft */) {
658
+ emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0);
659
+ }
660
+ scnr.next();
661
+ token = getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */);
662
+ context.braceNest--;
663
+ context.braceNest > 0 && skipSpaces(scnr);
664
+ if (context.inLinked && context.braceNest === 0) {
665
+ context.inLinked = false;
666
+ }
667
+ return token;
668
+ case "@" /* TokenChars.LinkedAlias */:
669
+ if (context.braceNest > 0) {
670
+ emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
671
+ }
672
+ token = readTokenInLinked(scnr, context) || getEndToken(context);
673
+ context.braceNest = 0;
674
+ return token;
675
+ default:
676
+ let validNamedIdentifier = true;
677
+ let validListIdentifier = true;
678
+ let validLiteral = true;
679
+ if (isPluralStart(scnr)) {
680
+ if (context.braceNest > 0) {
681
+ emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
682
+ }
683
+ token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr));
684
+ // reset
685
+ context.braceNest = 0;
686
+ context.inLinked = false;
687
+ return token;
688
+ }
689
+ if (context.braceNest > 0 &&
690
+ (context.currentType === 5 /* TokenTypes.Named */ ||
691
+ context.currentType === 6 /* TokenTypes.List */ ||
692
+ context.currentType === 7 /* TokenTypes.Literal */)) {
693
+ emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0);
694
+ context.braceNest = 0;
695
+ return readToken(scnr, context);
696
+ }
697
+ if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) {
698
+ token = getToken(context, 5 /* TokenTypes.Named */, readNamedIdentifier(scnr));
699
+ skipSpaces(scnr);
700
+ return token;
701
+ }
702
+ if ((validListIdentifier = isListIdentifierStart(scnr, context))) {
703
+ token = getToken(context, 6 /* TokenTypes.List */, readListIdentifier(scnr));
704
+ skipSpaces(scnr);
705
+ return token;
706
+ }
707
+ if ((validLiteral = isLiteralStart(scnr, context))) {
708
+ token = getToken(context, 7 /* TokenTypes.Literal */, readLiteral(scnr));
709
+ skipSpaces(scnr);
710
+ return token;
711
+ }
712
+ if (!validNamedIdentifier && !validListIdentifier && !validLiteral) {
713
+ // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ...
714
+ token = getToken(context, 13 /* TokenTypes.InvalidPlace */, readInvalidIdentifier(scnr));
715
+ emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value);
716
+ skipSpaces(scnr);
717
+ return token;
718
+ }
719
+ break;
720
+ }
721
+ return token;
722
+ }
723
+ // TODO: We need refactoring of token parsing ...
724
+ function readTokenInLinked(scnr, context) {
725
+ const { currentType } = context;
726
+ let token = null;
727
+ const ch = scnr.currentChar();
728
+ if ((currentType === 8 /* TokenTypes.LinkedAlias */ ||
729
+ currentType === 9 /* TokenTypes.LinkedDot */ ||
730
+ currentType === 12 /* TokenTypes.LinkedModifier */ ||
731
+ currentType === 10 /* TokenTypes.LinkedDelimiter */) &&
732
+ (ch === CHAR_LF || ch === CHAR_SP)) {
733
+ emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0);
734
+ }
735
+ switch (ch) {
736
+ case "@" /* TokenChars.LinkedAlias */:
737
+ scnr.next();
738
+ token = getToken(context, 8 /* TokenTypes.LinkedAlias */, "@" /* TokenChars.LinkedAlias */);
739
+ context.inLinked = true;
740
+ return token;
741
+ case "." /* TokenChars.LinkedDot */:
742
+ skipSpaces(scnr);
743
+ scnr.next();
744
+ return getToken(context, 9 /* TokenTypes.LinkedDot */, "." /* TokenChars.LinkedDot */);
745
+ case ":" /* TokenChars.LinkedDelimiter */:
746
+ skipSpaces(scnr);
747
+ scnr.next();
748
+ return getToken(context, 10 /* TokenTypes.LinkedDelimiter */, ":" /* TokenChars.LinkedDelimiter */);
749
+ default:
750
+ if (isPluralStart(scnr)) {
751
+ token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr));
752
+ // reset
753
+ context.braceNest = 0;
754
+ context.inLinked = false;
755
+ return token;
756
+ }
757
+ if (isLinkedDotStart(scnr, context) ||
758
+ isLinkedDelimiterStart(scnr, context)) {
759
+ skipSpaces(scnr);
760
+ return readTokenInLinked(scnr, context);
761
+ }
762
+ if (isLinkedModifierStart(scnr, context)) {
763
+ skipSpaces(scnr);
764
+ return getToken(context, 12 /* TokenTypes.LinkedModifier */, readLinkedModifier(scnr));
765
+ }
766
+ if (isLinkedReferStart(scnr, context)) {
767
+ skipSpaces(scnr);
768
+ if (ch === "{" /* TokenChars.BraceLeft */) {
769
+ // scan the placeholder
770
+ return readTokenInPlaceholder(scnr, context) || token;
771
+ }
772
+ else {
773
+ return getToken(context, 11 /* TokenTypes.LinkedKey */, readLinkedRefer(scnr));
774
+ }
775
+ }
776
+ if (currentType === 8 /* TokenTypes.LinkedAlias */) {
777
+ emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0);
778
+ }
779
+ context.braceNest = 0;
780
+ context.inLinked = false;
781
+ return readToken(scnr, context);
782
+ }
783
+ }
784
+ // TODO: We need refactoring of token parsing ...
785
+ function readToken(scnr, context) {
786
+ let token = { type: 14 /* TokenTypes.EOF */ };
787
+ if (context.braceNest > 0) {
788
+ return readTokenInPlaceholder(scnr, context) || getEndToken(context);
789
+ }
790
+ if (context.inLinked) {
791
+ return readTokenInLinked(scnr, context) || getEndToken(context);
792
+ }
793
+ const ch = scnr.currentChar();
794
+ switch (ch) {
795
+ case "{" /* TokenChars.BraceLeft */:
796
+ return readTokenInPlaceholder(scnr, context) || getEndToken(context);
797
+ case "}" /* TokenChars.BraceRight */:
798
+ emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0);
799
+ scnr.next();
800
+ return getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */);
801
+ case "@" /* TokenChars.LinkedAlias */:
802
+ return readTokenInLinked(scnr, context) || getEndToken(context);
803
+ default:
804
+ if (isPluralStart(scnr)) {
805
+ token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr));
806
+ // reset
807
+ context.braceNest = 0;
808
+ context.inLinked = false;
809
+ return token;
810
+ }
811
+ const { isModulo, hasSpace } = detectModuloStart(scnr);
812
+ if (isModulo) {
813
+ return hasSpace
814
+ ? getToken(context, 0 /* TokenTypes.Text */, readText(scnr))
815
+ : getToken(context, 4 /* TokenTypes.Modulo */, readModulo(scnr));
816
+ }
817
+ if (isTextStart(scnr)) {
818
+ return getToken(context, 0 /* TokenTypes.Text */, readText(scnr));
819
+ }
820
+ break;
821
+ }
822
+ return token;
823
+ }
824
+ function nextToken() {
825
+ const { currentType, offset, startLoc, endLoc } = _context;
826
+ _context.lastType = currentType;
827
+ _context.lastOffset = offset;
828
+ _context.lastStartLoc = startLoc;
829
+ _context.lastEndLoc = endLoc;
830
+ _context.offset = currentOffset();
831
+ _context.startLoc = currentPosition();
832
+ if (_scnr.currentChar() === EOF) {
833
+ return getToken(_context, 14 /* TokenTypes.EOF */);
834
+ }
835
+ return readToken(_scnr, _context);
836
+ }
837
+ return {
838
+ nextToken,
839
+ currentOffset,
840
+ currentPosition,
841
+ context
842
+ };
830
843
  }
831
844
 
832
- const ERROR_DOMAIN = 'parser';
833
- // Backslash backslash, backslash quote, uHHHH, UHHHHHH.
834
- const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
835
- function fromEscapeSequence(match, codePoint4, codePoint6) {
836
- switch (match) {
837
- case `\\\\`:
838
- return `\\`;
839
- case `\\\'`:
840
- return `\'`;
841
- default: {
842
- const codePoint = parseInt(codePoint4 || codePoint6, 16);
843
- if (codePoint <= 0xd7ff || codePoint >= 0xe000) {
844
- return String.fromCodePoint(codePoint);
845
- }
846
- // invalid ...
847
- // Replace them with U+FFFD REPLACEMENT CHARACTER.
848
- return '�';
849
- }
850
- }
851
- }
852
- function createParser(options = {}) {
853
- const location = options.location !== false;
854
- const { onError } = options;
855
- function emitError(tokenzer, code, start, offset, ...args) {
856
- const end = tokenzer.currentPosition();
857
- end.offset += offset;
858
- end.column += offset;
859
- if (onError) {
860
- const loc = createLocation(start, end);
861
- const err = createCompileError(code, loc, {
862
- domain: ERROR_DOMAIN,
863
- args
864
- });
865
- onError(err);
866
- }
867
- }
868
- function startNode(type, offset, loc) {
869
- const node = {
870
- type,
871
- start: offset,
872
- end: offset
873
- };
874
- if (location) {
875
- node.loc = { start: loc, end: loc };
876
- }
877
- return node;
878
- }
879
- function endNode(node, offset, pos, type) {
880
- node.end = offset;
881
- if (type) {
882
- node.type = type;
883
- }
884
- if (location && node.loc) {
885
- node.loc.end = pos;
886
- }
887
- }
888
- function parseText(tokenizer, value) {
889
- const context = tokenizer.context();
890
- const node = startNode(3 /* Text */, context.offset, context.startLoc);
891
- node.value = value;
892
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
893
- return node;
894
- }
895
- function parseList(tokenizer, index) {
896
- const context = tokenizer.context();
897
- const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
898
- const node = startNode(5 /* List */, offset, loc);
899
- node.index = parseInt(index, 10);
900
- tokenizer.nextToken(); // skip brach right
901
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
902
- return node;
903
- }
904
- function parseNamed(tokenizer, key) {
905
- const context = tokenizer.context();
906
- const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
907
- const node = startNode(4 /* Named */, offset, loc);
908
- node.key = key;
909
- tokenizer.nextToken(); // skip brach right
910
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
911
- return node;
912
- }
913
- function parseLiteral(tokenizer, value) {
914
- const context = tokenizer.context();
915
- const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
916
- const node = startNode(9 /* Literal */, offset, loc);
917
- node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence);
918
- tokenizer.nextToken(); // skip brach right
919
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
920
- return node;
921
- }
922
- function parseLinkedModifier(tokenizer) {
923
- const token = tokenizer.nextToken();
924
- const context = tokenizer.context();
925
- const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc
926
- const node = startNode(8 /* LinkedModifier */, offset, loc);
927
- if (token.type !== 12 /* LinkedModifier */) {
928
- // empty modifier
929
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0);
930
- node.value = '';
931
- endNode(node, offset, loc);
932
- return {
933
- nextConsumeToken: token,
934
- node
935
- };
936
- }
937
- // check token
938
- if (token.value == null) {
939
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
940
- }
941
- node.value = token.value || '';
942
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
943
- return {
944
- node
945
- };
946
- }
947
- function parseLinkedKey(tokenizer, value) {
948
- const context = tokenizer.context();
949
- const node = startNode(7 /* LinkedKey */, context.offset, context.startLoc);
950
- node.value = value;
951
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
952
- return node;
953
- }
954
- function parseLinked(tokenizer) {
955
- const context = tokenizer.context();
956
- const linkedNode = startNode(6 /* Linked */, context.offset, context.startLoc);
957
- let token = tokenizer.nextToken();
958
- if (token.type === 9 /* LinkedDot */) {
959
- const parsed = parseLinkedModifier(tokenizer);
960
- linkedNode.modifier = parsed.node;
961
- token = parsed.nextConsumeToken || tokenizer.nextToken();
962
- }
963
- // asset check token
964
- if (token.type !== 10 /* LinkedDelimiter */) {
965
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
966
- }
967
- token = tokenizer.nextToken();
968
- // skip brace left
969
- if (token.type === 2 /* BraceLeft */) {
970
- token = tokenizer.nextToken();
971
- }
972
- switch (token.type) {
973
- case 11 /* LinkedKey */:
974
- if (token.value == null) {
975
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
976
- }
977
- linkedNode.key = parseLinkedKey(tokenizer, token.value || '');
978
- break;
979
- case 5 /* Named */:
980
- if (token.value == null) {
981
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
982
- }
983
- linkedNode.key = parseNamed(tokenizer, token.value || '');
984
- break;
985
- case 6 /* List */:
986
- if (token.value == null) {
987
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
988
- }
989
- linkedNode.key = parseList(tokenizer, token.value || '');
990
- break;
991
- case 7 /* Literal */:
992
- if (token.value == null) {
993
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
994
- }
995
- linkedNode.key = parseLiteral(tokenizer, token.value || '');
996
- break;
997
- default:
998
- // empty key
999
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0);
1000
- const nextContext = tokenizer.context();
1001
- const emptyLinkedKeyNode = startNode(7 /* LinkedKey */, nextContext.offset, nextContext.startLoc);
1002
- emptyLinkedKeyNode.value = '';
1003
- endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc);
1004
- linkedNode.key = emptyLinkedKeyNode;
1005
- endNode(linkedNode, nextContext.offset, nextContext.startLoc);
1006
- return {
1007
- nextConsumeToken: token,
1008
- node: linkedNode
1009
- };
1010
- }
1011
- endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition());
1012
- return {
1013
- node: linkedNode
1014
- };
1015
- }
1016
- function parseMessage(tokenizer) {
1017
- const context = tokenizer.context();
1018
- const startOffset = context.currentType === 1 /* Pipe */
1019
- ? tokenizer.currentOffset()
1020
- : context.offset;
1021
- const startLoc = context.currentType === 1 /* Pipe */
1022
- ? context.endLoc
1023
- : context.startLoc;
1024
- const node = startNode(2 /* Message */, startOffset, startLoc);
1025
- node.items = [];
1026
- let nextToken = null;
1027
- do {
1028
- const token = nextToken || tokenizer.nextToken();
1029
- nextToken = null;
1030
- switch (token.type) {
1031
- case 0 /* Text */:
1032
- if (token.value == null) {
1033
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1034
- }
1035
- node.items.push(parseText(tokenizer, token.value || ''));
1036
- break;
1037
- case 6 /* List */:
1038
- if (token.value == null) {
1039
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1040
- }
1041
- node.items.push(parseList(tokenizer, token.value || ''));
1042
- break;
1043
- case 5 /* Named */:
1044
- if (token.value == null) {
1045
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1046
- }
1047
- node.items.push(parseNamed(tokenizer, token.value || ''));
1048
- break;
1049
- case 7 /* Literal */:
1050
- if (token.value == null) {
1051
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1052
- }
1053
- node.items.push(parseLiteral(tokenizer, token.value || ''));
1054
- break;
1055
- case 8 /* LinkedAlias */:
1056
- const parsed = parseLinked(tokenizer);
1057
- node.items.push(parsed.node);
1058
- nextToken = parsed.nextConsumeToken || null;
1059
- break;
1060
- }
1061
- } while (context.currentType !== 14 /* EOF */ &&
1062
- context.currentType !== 1 /* Pipe */);
1063
- // adjust message node loc
1064
- const endOffset = context.currentType === 1 /* Pipe */
1065
- ? context.lastOffset
1066
- : tokenizer.currentOffset();
1067
- const endLoc = context.currentType === 1 /* Pipe */
1068
- ? context.lastEndLoc
1069
- : tokenizer.currentPosition();
1070
- endNode(node, endOffset, endLoc);
1071
- return node;
1072
- }
1073
- function parsePlural(tokenizer, offset, loc, msgNode) {
1074
- const context = tokenizer.context();
1075
- let hasEmptyMessage = msgNode.items.length === 0;
1076
- const node = startNode(1 /* Plural */, offset, loc);
1077
- node.cases = [];
1078
- node.cases.push(msgNode);
1079
- do {
1080
- const msg = parseMessage(tokenizer);
1081
- if (!hasEmptyMessage) {
1082
- hasEmptyMessage = msg.items.length === 0;
1083
- }
1084
- node.cases.push(msg);
1085
- } while (context.currentType !== 14 /* EOF */);
1086
- if (hasEmptyMessage) {
1087
- emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0);
1088
- }
1089
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1090
- return node;
1091
- }
1092
- function parseResource(tokenizer) {
1093
- const context = tokenizer.context();
1094
- const { offset, startLoc } = context;
1095
- const msgNode = parseMessage(tokenizer);
1096
- if (context.currentType === 14 /* EOF */) {
1097
- return msgNode;
1098
- }
1099
- else {
1100
- return parsePlural(tokenizer, offset, startLoc, msgNode);
1101
- }
1102
- }
1103
- function parse(source) {
1104
- const tokenizer = createTokenizer(source, shared.assign({}, options));
1105
- const context = tokenizer.context();
1106
- const node = startNode(0 /* Resource */, context.offset, context.startLoc);
1107
- if (location && node.loc) {
1108
- node.loc.source = source;
1109
- }
1110
- node.body = parseResource(tokenizer);
1111
- // assert whether achieved to EOF
1112
- if (context.currentType !== 14 /* EOF */) {
1113
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || '');
1114
- }
1115
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1116
- return node;
1117
- }
1118
- return { parse };
1119
- }
1120
- function getTokenCaption(token) {
1121
- if (token.type === 14 /* EOF */) {
1122
- return 'EOF';
1123
- }
1124
- const name = (token.value || '').replace(/\r?\n/gu, '\\n');
1125
- return name.length > 10 ? name.slice(0, 9) + '' : name;
845
+ const ERROR_DOMAIN = 'parser';
846
+ // Backslash backslash, backslash quote, uHHHH, UHHHHHH.
847
+ const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
848
+ function fromEscapeSequence(match, codePoint4, codePoint6) {
849
+ switch (match) {
850
+ case `\\\\`:
851
+ return `\\`;
852
+ case `\\\'`:
853
+ return `\'`;
854
+ default: {
855
+ const codePoint = parseInt(codePoint4 || codePoint6, 16);
856
+ if (codePoint <= 0xd7ff || codePoint >= 0xe000) {
857
+ return String.fromCodePoint(codePoint);
858
+ }
859
+ // invalid ...
860
+ // Replace them with U+FFFD REPLACEMENT CHARACTER.
861
+ return '�';
862
+ }
863
+ }
864
+ }
865
+ function createParser(options = {}) {
866
+ const location = options.location !== false;
867
+ const { onError } = options;
868
+ function emitError(tokenzer, code, start, offset, ...args) {
869
+ const end = tokenzer.currentPosition();
870
+ end.offset += offset;
871
+ end.column += offset;
872
+ if (onError) {
873
+ const loc = location ? createLocation(start, end) : null;
874
+ const err = createCompileError(code, loc, {
875
+ domain: ERROR_DOMAIN,
876
+ args
877
+ });
878
+ onError(err);
879
+ }
880
+ }
881
+ function startNode(type, offset, loc) {
882
+ const node = { type };
883
+ if (location) {
884
+ node.start = offset;
885
+ node.end = offset;
886
+ node.loc = { start: loc, end: loc };
887
+ }
888
+ return node;
889
+ }
890
+ function endNode(node, offset, pos, type) {
891
+ if (type) {
892
+ node.type = type;
893
+ }
894
+ if (location) {
895
+ node.end = offset;
896
+ if (node.loc) {
897
+ node.loc.end = pos;
898
+ }
899
+ }
900
+ }
901
+ function parseText(tokenizer, value) {
902
+ const context = tokenizer.context();
903
+ const node = startNode(3 /* NodeTypes.Text */, context.offset, context.startLoc);
904
+ node.value = value;
905
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
906
+ return node;
907
+ }
908
+ function parseList(tokenizer, index) {
909
+ const context = tokenizer.context();
910
+ const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
911
+ const node = startNode(5 /* NodeTypes.List */, offset, loc);
912
+ node.index = parseInt(index, 10);
913
+ tokenizer.nextToken(); // skip brach right
914
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
915
+ return node;
916
+ }
917
+ function parseNamed(tokenizer, key) {
918
+ const context = tokenizer.context();
919
+ const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
920
+ const node = startNode(4 /* NodeTypes.Named */, offset, loc);
921
+ node.key = key;
922
+ tokenizer.nextToken(); // skip brach right
923
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
924
+ return node;
925
+ }
926
+ function parseLiteral(tokenizer, value) {
927
+ const context = tokenizer.context();
928
+ const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
929
+ const node = startNode(9 /* NodeTypes.Literal */, offset, loc);
930
+ node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence);
931
+ tokenizer.nextToken(); // skip brach right
932
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
933
+ return node;
934
+ }
935
+ function parseLinkedModifier(tokenizer) {
936
+ const token = tokenizer.nextToken();
937
+ const context = tokenizer.context();
938
+ const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc
939
+ const node = startNode(8 /* NodeTypes.LinkedModifier */, offset, loc);
940
+ if (token.type !== 12 /* TokenTypes.LinkedModifier */) {
941
+ // empty modifier
942
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0);
943
+ node.value = '';
944
+ endNode(node, offset, loc);
945
+ return {
946
+ nextConsumeToken: token,
947
+ node
948
+ };
949
+ }
950
+ // check token
951
+ if (token.value == null) {
952
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
953
+ }
954
+ node.value = token.value || '';
955
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
956
+ return {
957
+ node
958
+ };
959
+ }
960
+ function parseLinkedKey(tokenizer, value) {
961
+ const context = tokenizer.context();
962
+ const node = startNode(7 /* NodeTypes.LinkedKey */, context.offset, context.startLoc);
963
+ node.value = value;
964
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
965
+ return node;
966
+ }
967
+ function parseLinked(tokenizer) {
968
+ const context = tokenizer.context();
969
+ const linkedNode = startNode(6 /* NodeTypes.Linked */, context.offset, context.startLoc);
970
+ let token = tokenizer.nextToken();
971
+ if (token.type === 9 /* TokenTypes.LinkedDot */) {
972
+ const parsed = parseLinkedModifier(tokenizer);
973
+ linkedNode.modifier = parsed.node;
974
+ token = parsed.nextConsumeToken || tokenizer.nextToken();
975
+ }
976
+ // asset check token
977
+ if (token.type !== 10 /* TokenTypes.LinkedDelimiter */) {
978
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
979
+ }
980
+ token = tokenizer.nextToken();
981
+ // skip brace left
982
+ if (token.type === 2 /* TokenTypes.BraceLeft */) {
983
+ token = tokenizer.nextToken();
984
+ }
985
+ switch (token.type) {
986
+ case 11 /* TokenTypes.LinkedKey */:
987
+ if (token.value == null) {
988
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
989
+ }
990
+ linkedNode.key = parseLinkedKey(tokenizer, token.value || '');
991
+ break;
992
+ case 5 /* TokenTypes.Named */:
993
+ if (token.value == null) {
994
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
995
+ }
996
+ linkedNode.key = parseNamed(tokenizer, token.value || '');
997
+ break;
998
+ case 6 /* TokenTypes.List */:
999
+ if (token.value == null) {
1000
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1001
+ }
1002
+ linkedNode.key = parseList(tokenizer, token.value || '');
1003
+ break;
1004
+ case 7 /* TokenTypes.Literal */:
1005
+ if (token.value == null) {
1006
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1007
+ }
1008
+ linkedNode.key = parseLiteral(tokenizer, token.value || '');
1009
+ break;
1010
+ default:
1011
+ // empty key
1012
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0);
1013
+ const nextContext = tokenizer.context();
1014
+ const emptyLinkedKeyNode = startNode(7 /* NodeTypes.LinkedKey */, nextContext.offset, nextContext.startLoc);
1015
+ emptyLinkedKeyNode.value = '';
1016
+ endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc);
1017
+ linkedNode.key = emptyLinkedKeyNode;
1018
+ endNode(linkedNode, nextContext.offset, nextContext.startLoc);
1019
+ return {
1020
+ nextConsumeToken: token,
1021
+ node: linkedNode
1022
+ };
1023
+ }
1024
+ endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition());
1025
+ return {
1026
+ node: linkedNode
1027
+ };
1028
+ }
1029
+ function parseMessage(tokenizer) {
1030
+ const context = tokenizer.context();
1031
+ const startOffset = context.currentType === 1 /* TokenTypes.Pipe */
1032
+ ? tokenizer.currentOffset()
1033
+ : context.offset;
1034
+ const startLoc = context.currentType === 1 /* TokenTypes.Pipe */
1035
+ ? context.endLoc
1036
+ : context.startLoc;
1037
+ const node = startNode(2 /* NodeTypes.Message */, startOffset, startLoc);
1038
+ node.items = [];
1039
+ let nextToken = null;
1040
+ do {
1041
+ const token = nextToken || tokenizer.nextToken();
1042
+ nextToken = null;
1043
+ switch (token.type) {
1044
+ case 0 /* TokenTypes.Text */:
1045
+ if (token.value == null) {
1046
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1047
+ }
1048
+ node.items.push(parseText(tokenizer, token.value || ''));
1049
+ break;
1050
+ case 6 /* TokenTypes.List */:
1051
+ if (token.value == null) {
1052
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1053
+ }
1054
+ node.items.push(parseList(tokenizer, token.value || ''));
1055
+ break;
1056
+ case 5 /* TokenTypes.Named */:
1057
+ if (token.value == null) {
1058
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1059
+ }
1060
+ node.items.push(parseNamed(tokenizer, token.value || ''));
1061
+ break;
1062
+ case 7 /* TokenTypes.Literal */:
1063
+ if (token.value == null) {
1064
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token));
1065
+ }
1066
+ node.items.push(parseLiteral(tokenizer, token.value || ''));
1067
+ break;
1068
+ case 8 /* TokenTypes.LinkedAlias */:
1069
+ const parsed = parseLinked(tokenizer);
1070
+ node.items.push(parsed.node);
1071
+ nextToken = parsed.nextConsumeToken || null;
1072
+ break;
1073
+ }
1074
+ } while (context.currentType !== 14 /* TokenTypes.EOF */ &&
1075
+ context.currentType !== 1 /* TokenTypes.Pipe */);
1076
+ // adjust message node loc
1077
+ const endOffset = context.currentType === 1 /* TokenTypes.Pipe */
1078
+ ? context.lastOffset
1079
+ : tokenizer.currentOffset();
1080
+ const endLoc = context.currentType === 1 /* TokenTypes.Pipe */
1081
+ ? context.lastEndLoc
1082
+ : tokenizer.currentPosition();
1083
+ endNode(node, endOffset, endLoc);
1084
+ return node;
1085
+ }
1086
+ function parsePlural(tokenizer, offset, loc, msgNode) {
1087
+ const context = tokenizer.context();
1088
+ let hasEmptyMessage = msgNode.items.length === 0;
1089
+ const node = startNode(1 /* NodeTypes.Plural */, offset, loc);
1090
+ node.cases = [];
1091
+ node.cases.push(msgNode);
1092
+ do {
1093
+ const msg = parseMessage(tokenizer);
1094
+ if (!hasEmptyMessage) {
1095
+ hasEmptyMessage = msg.items.length === 0;
1096
+ }
1097
+ node.cases.push(msg);
1098
+ } while (context.currentType !== 14 /* TokenTypes.EOF */);
1099
+ if (hasEmptyMessage) {
1100
+ emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0);
1101
+ }
1102
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1103
+ return node;
1104
+ }
1105
+ function parseResource(tokenizer) {
1106
+ const context = tokenizer.context();
1107
+ const { offset, startLoc } = context;
1108
+ const msgNode = parseMessage(tokenizer);
1109
+ if (context.currentType === 14 /* TokenTypes.EOF */) {
1110
+ return msgNode;
1111
+ }
1112
+ else {
1113
+ return parsePlural(tokenizer, offset, startLoc, msgNode);
1114
+ }
1115
+ }
1116
+ function parse(source) {
1117
+ const tokenizer = createTokenizer(source, shared.assign({}, options));
1118
+ const context = tokenizer.context();
1119
+ const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc);
1120
+ if (location && node.loc) {
1121
+ node.loc.source = source;
1122
+ }
1123
+ node.body = parseResource(tokenizer);
1124
+ if (options.onCacheKey) {
1125
+ node.cacheKey = options.onCacheKey(source);
1126
+ }
1127
+ // assert whether achieved to EOF
1128
+ if (context.currentType !== 14 /* TokenTypes.EOF */) {
1129
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || '');
1130
+ }
1131
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1132
+ return node;
1133
+ }
1134
+ return { parse };
1135
+ }
1136
+ function getTokenCaption(token) {
1137
+ if (token.type === 14 /* TokenTypes.EOF */) {
1138
+ return 'EOF';
1139
+ }
1140
+ const name = (token.value || '').replace(/\r?\n/gu, '\\n');
1141
+ return name.length > 10 ? name.slice(0, 9) + '…' : name;
1126
1142
  }
1127
1143
 
1128
- function createTransformer(ast, options = {} // eslint-disable-line
1129
- ) {
1130
- const _context = {
1131
- ast,
1132
- helpers: new Set()
1133
- };
1134
- const context = () => _context;
1135
- const helper = (name) => {
1136
- _context.helpers.add(name);
1137
- return name;
1138
- };
1139
- return { context, helper };
1140
- }
1141
- function traverseNodes(nodes, transformer) {
1142
- for (let i = 0; i < nodes.length; i++) {
1143
- traverseNode(nodes[i], transformer);
1144
- }
1145
- }
1146
- function traverseNode(node, transformer) {
1147
- // TODO: if we need pre-hook of transform, should be implemented to here
1148
- switch (node.type) {
1149
- case 1 /* Plural */:
1150
- traverseNodes(node.cases, transformer);
1151
- transformer.helper("plural" /* PLURAL */);
1152
- break;
1153
- case 2 /* Message */:
1154
- traverseNodes(node.items, transformer);
1155
- break;
1156
- case 6 /* Linked */:
1157
- const linked = node;
1158
- traverseNode(linked.key, transformer);
1159
- transformer.helper("linked" /* LINKED */);
1160
- transformer.helper("type" /* TYPE */);
1161
- break;
1162
- case 5 /* List */:
1163
- transformer.helper("interpolate" /* INTERPOLATE */);
1164
- transformer.helper("list" /* LIST */);
1165
- break;
1166
- case 4 /* Named */:
1167
- transformer.helper("interpolate" /* INTERPOLATE */);
1168
- transformer.helper("named" /* NAMED */);
1169
- break;
1170
- }
1171
- // TODO: if we need post-hook of transform, should be implemented to here
1172
- }
1173
- // transform AST
1174
- function transform(ast, options = {} // eslint-disable-line
1175
- ) {
1176
- const transformer = createTransformer(ast);
1177
- transformer.helper("normalize" /* NORMALIZE */);
1178
- // traverse
1179
- ast.body && traverseNode(ast.body, transformer);
1180
- // set meta information
1181
- const context = transformer.context();
1182
- ast.helpers = Array.from(context.helpers);
1144
+ function createTransformer(ast, options = {} // eslint-disable-line
1145
+ ) {
1146
+ const _context = {
1147
+ ast,
1148
+ helpers: new Set()
1149
+ };
1150
+ const context = () => _context;
1151
+ const helper = (name) => {
1152
+ _context.helpers.add(name);
1153
+ return name;
1154
+ };
1155
+ return { context, helper };
1156
+ }
1157
+ function traverseNodes(nodes, transformer) {
1158
+ for (let i = 0; i < nodes.length; i++) {
1159
+ traverseNode(nodes[i], transformer);
1160
+ }
1161
+ }
1162
+ function traverseNode(node, transformer) {
1163
+ // TODO: if we need pre-hook of transform, should be implemented to here
1164
+ switch (node.type) {
1165
+ case 1 /* NodeTypes.Plural */:
1166
+ traverseNodes(node.cases, transformer);
1167
+ transformer.helper("plural" /* HelperNameMap.PLURAL */);
1168
+ break;
1169
+ case 2 /* NodeTypes.Message */:
1170
+ traverseNodes(node.items, transformer);
1171
+ break;
1172
+ case 6 /* NodeTypes.Linked */:
1173
+ const linked = node;
1174
+ traverseNode(linked.key, transformer);
1175
+ transformer.helper("linked" /* HelperNameMap.LINKED */);
1176
+ transformer.helper("type" /* HelperNameMap.TYPE */);
1177
+ break;
1178
+ case 5 /* NodeTypes.List */:
1179
+ transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
1180
+ transformer.helper("list" /* HelperNameMap.LIST */);
1181
+ break;
1182
+ case 4 /* NodeTypes.Named */:
1183
+ transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
1184
+ transformer.helper("named" /* HelperNameMap.NAMED */);
1185
+ break;
1186
+ }
1187
+ // TODO: if we need post-hook of transform, should be implemented to here
1188
+ }
1189
+ // transform AST
1190
+ function transform(ast, options = {} // eslint-disable-line
1191
+ ) {
1192
+ const transformer = createTransformer(ast);
1193
+ transformer.helper("normalize" /* HelperNameMap.NORMALIZE */);
1194
+ // traverse
1195
+ ast.body && traverseNode(ast.body, transformer);
1196
+ // set meta information
1197
+ const context = transformer.context();
1198
+ ast.helpers = Array.from(context.helpers);
1183
1199
  }
1184
1200
 
1185
- function createCodeGenerator(ast, options) {
1186
- const { sourceMap: sourceMap$1, filename, breakLineCode, needIndent: _needIndent } = options;
1187
- const _context = {
1188
- source: ast.loc.source,
1189
- filename,
1190
- code: '',
1191
- column: 1,
1192
- line: 1,
1193
- offset: 0,
1194
- map: undefined,
1195
- breakLineCode,
1196
- needIndent: _needIndent,
1197
- indentLevel: 0
1198
- };
1199
- const context = () => _context;
1200
- function push(code, node) {
1201
- _context.code += code;
1202
- if (_context.map) {
1203
- if (node && node.loc && node.loc !== LocationStub) {
1204
- addMapping(node.loc.start, getMappingName(node));
1205
- }
1206
- advancePositionWithSource(_context, code);
1207
- }
1208
- }
1209
- function _newline(n, withBreakLine = true) {
1210
- const _breakLineCode = withBreakLine ? breakLineCode : '';
1211
- push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
1212
- }
1213
- function indent(withNewLine = true) {
1214
- const level = ++_context.indentLevel;
1215
- withNewLine && _newline(level);
1216
- }
1217
- function deindent(withNewLine = true) {
1218
- const level = --_context.indentLevel;
1219
- withNewLine && _newline(level);
1220
- }
1221
- function newline() {
1222
- _newline(_context.indentLevel);
1223
- }
1224
- const helper = (key) => `_${key}`;
1225
- const needIndent = () => _context.needIndent;
1226
- function addMapping(loc, name) {
1227
- _context.map.addMapping({
1228
- name,
1229
- source: _context.filename,
1230
- original: {
1231
- line: loc.line,
1232
- column: loc.column - 1
1233
- },
1234
- generated: {
1235
- line: _context.line,
1236
- column: _context.column - 1
1237
- }
1238
- });
1239
- }
1240
- if (sourceMap$1) {
1241
- _context.map = new sourceMap.SourceMapGenerator();
1242
- _context.map.setSourceContent(filename, _context.source);
1243
- }
1244
- return {
1245
- context,
1246
- push,
1247
- indent,
1248
- deindent,
1249
- newline,
1250
- helper,
1251
- needIndent
1252
- };
1253
- }
1254
- function generateLinkedNode(generator, node) {
1255
- const { helper } = generator;
1256
- generator.push(`${helper("linked" /* LINKED */)}(`);
1257
- generateNode(generator, node.key);
1258
- if (node.modifier) {
1259
- generator.push(`, `);
1260
- generateNode(generator, node.modifier);
1261
- generator.push(`, _type`);
1262
- }
1263
- else {
1264
- generator.push(`, undefined, _type`);
1265
- }
1266
- generator.push(`)`);
1267
- }
1268
- function generateMessageNode(generator, node) {
1269
- const { helper, needIndent } = generator;
1270
- generator.push(`${helper("normalize" /* NORMALIZE */)}([`);
1271
- generator.indent(needIndent());
1272
- const length = node.items.length;
1273
- for (let i = 0; i < length; i++) {
1274
- generateNode(generator, node.items[i]);
1275
- if (i === length - 1) {
1276
- break;
1277
- }
1278
- generator.push(', ');
1279
- }
1280
- generator.deindent(needIndent());
1281
- generator.push('])');
1282
- }
1283
- function generatePluralNode(generator, node) {
1284
- const { helper, needIndent } = generator;
1285
- if (node.cases.length > 1) {
1286
- generator.push(`${helper("plural" /* PLURAL */)}([`);
1287
- generator.indent(needIndent());
1288
- const length = node.cases.length;
1289
- for (let i = 0; i < length; i++) {
1290
- generateNode(generator, node.cases[i]);
1291
- if (i === length - 1) {
1292
- break;
1293
- }
1294
- generator.push(', ');
1295
- }
1296
- generator.deindent(needIndent());
1297
- generator.push(`])`);
1298
- }
1299
- }
1300
- function generateResource(generator, node) {
1301
- if (node.body) {
1302
- generateNode(generator, node.body);
1303
- }
1304
- else {
1305
- generator.push('null');
1306
- }
1307
- }
1308
- function generateNode(generator, node) {
1309
- const { helper } = generator;
1310
- switch (node.type) {
1311
- case 0 /* Resource */:
1312
- generateResource(generator, node);
1313
- break;
1314
- case 1 /* Plural */:
1315
- generatePluralNode(generator, node);
1316
- break;
1317
- case 2 /* Message */:
1318
- generateMessageNode(generator, node);
1319
- break;
1320
- case 6 /* Linked */:
1321
- generateLinkedNode(generator, node);
1322
- break;
1323
- case 8 /* LinkedModifier */:
1324
- generator.push(JSON.stringify(node.value), node);
1325
- break;
1326
- case 7 /* LinkedKey */:
1327
- generator.push(JSON.stringify(node.value), node);
1328
- break;
1329
- case 5 /* List */:
1330
- generator.push(`${helper("interpolate" /* INTERPOLATE */)}(${helper("list" /* LIST */)}(${node.index}))`, node);
1331
- break;
1332
- case 4 /* Named */:
1333
- generator.push(`${helper("interpolate" /* INTERPOLATE */)}(${helper("named" /* NAMED */)}(${JSON.stringify(node.key)}))`, node);
1334
- break;
1335
- case 9 /* Literal */:
1336
- generator.push(JSON.stringify(node.value), node);
1337
- break;
1338
- case 3 /* Text */:
1339
- generator.push(JSON.stringify(node.value), node);
1340
- break;
1341
- }
1342
- }
1343
- // generate code from AST
1344
- const generate = (ast, options = {} // eslint-disable-line
1345
- ) => {
1346
- const mode = shared.isString(options.mode) ? options.mode : 'normal';
1347
- const filename = shared.isString(options.filename)
1348
- ? options.filename
1349
- : 'message.intl';
1350
- const sourceMap = !!options.sourceMap;
1351
- // prettier-ignore
1352
- const breakLineCode = options.breakLineCode != null
1353
- ? options.breakLineCode
1354
- : mode === 'arrow'
1355
- ? ';'
1356
- : '\n';
1357
- const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
1358
- const helpers = ast.helpers || [];
1359
- const generator = createCodeGenerator(ast, {
1360
- mode,
1361
- filename,
1362
- sourceMap,
1363
- breakLineCode,
1364
- needIndent
1365
- });
1366
- generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
1367
- generator.indent(needIndent);
1368
- if (helpers.length > 0) {
1369
- generator.push(`const { ${helpers.map(s => `${s}: _${s}`).join(', ')} } = ctx`);
1370
- generator.newline();
1371
- }
1372
- generator.push(`return `);
1373
- generateNode(generator, ast);
1374
- generator.deindent(needIndent);
1375
- generator.push(`}`);
1376
- const { code, map } = generator.context();
1377
- return {
1378
- ast,
1379
- code,
1380
- map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
1381
- };
1382
- };
1383
- function getMappingName(node) {
1384
- switch (node.type) {
1385
- case 3 /* Text */:
1386
- case 9 /* Literal */:
1387
- case 8 /* LinkedModifier */:
1388
- case 7 /* LinkedKey */:
1389
- return node.value;
1390
- case 5 /* List */:
1391
- return node.index.toString();
1392
- case 4 /* Named */:
1393
- return node.key;
1394
- default:
1395
- return undefined;
1396
- }
1397
- }
1398
- function advancePositionWithSource(pos, source, numberOfCharacters = source.length) {
1399
- let linesCount = 0;
1400
- let lastNewLinePos = -1;
1401
- for (let i = 0; i < numberOfCharacters; i++) {
1402
- if (source.charCodeAt(i) === 10 /* newline char code */) {
1403
- linesCount++;
1404
- lastNewLinePos = i;
1405
- }
1406
- }
1407
- pos.offset += numberOfCharacters;
1408
- pos.line += linesCount;
1409
- pos.column =
1410
- lastNewLinePos === -1
1411
- ? pos.column + numberOfCharacters
1412
- : numberOfCharacters - lastNewLinePos;
1413
- return pos;
1201
+ function optimize(ast) {
1202
+ const body = ast.body;
1203
+ if (body.type === 2 /* NodeTypes.Message */) {
1204
+ optimizeMessageNode(body);
1205
+ }
1206
+ else {
1207
+ body.cases.forEach(c => optimizeMessageNode(c));
1208
+ }
1209
+ return ast;
1210
+ }
1211
+ function optimizeMessageNode(message) {
1212
+ if (message.items.length === 1) {
1213
+ const item = message.items[0];
1214
+ if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
1215
+ message.static = item.value;
1216
+ delete item.value; // optimization for size
1217
+ }
1218
+ }
1219
+ else {
1220
+ const values = [];
1221
+ for (let i = 0; i < message.items.length; i++) {
1222
+ const item = message.items[i];
1223
+ if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) {
1224
+ break;
1225
+ }
1226
+ if (item.value == null) {
1227
+ break;
1228
+ }
1229
+ values.push(item.value);
1230
+ }
1231
+ if (values.length === message.items.length) {
1232
+ message.static = shared.join(values);
1233
+ for (let i = 0; i < message.items.length; i++) {
1234
+ const item = message.items[i];
1235
+ if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
1236
+ delete item.value; // optimization for size
1237
+ }
1238
+ }
1239
+ }
1240
+ }
1241
+ }
1242
+
1243
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1244
+ function minify(node) {
1245
+ node.t = node.type;
1246
+ switch (node.type) {
1247
+ case 0 /* NodeTypes.Resource */:
1248
+ const resource = node;
1249
+ minify(resource.body);
1250
+ resource.b = resource.body;
1251
+ delete resource.body;
1252
+ break;
1253
+ case 1 /* NodeTypes.Plural */:
1254
+ const plural = node;
1255
+ const cases = plural.cases;
1256
+ for (let i = 0; i < cases.length; i++) {
1257
+ minify(cases[i]);
1258
+ }
1259
+ plural.c = cases;
1260
+ delete plural.cases;
1261
+ break;
1262
+ case 2 /* NodeTypes.Message */:
1263
+ const message = node;
1264
+ const items = message.items;
1265
+ for (let i = 0; i < items.length; i++) {
1266
+ minify(items[i]);
1267
+ }
1268
+ message.i = items;
1269
+ delete message.items;
1270
+ if (message.static) {
1271
+ message.s = message.static;
1272
+ delete message.static;
1273
+ }
1274
+ break;
1275
+ case 3 /* NodeTypes.Text */:
1276
+ case 9 /* NodeTypes.Literal */:
1277
+ case 8 /* NodeTypes.LinkedModifier */:
1278
+ case 7 /* NodeTypes.LinkedKey */:
1279
+ const valueNode = node;
1280
+ if (valueNode.value) {
1281
+ valueNode.v = valueNode.value;
1282
+ delete valueNode.value;
1283
+ }
1284
+ break;
1285
+ case 6 /* NodeTypes.Linked */:
1286
+ const linked = node;
1287
+ minify(linked.key);
1288
+ linked.k = linked.key;
1289
+ delete linked.key;
1290
+ if (linked.modifier) {
1291
+ minify(linked.modifier);
1292
+ linked.m = linked.modifier;
1293
+ delete linked.modifier;
1294
+ }
1295
+ break;
1296
+ case 5 /* NodeTypes.List */:
1297
+ const list = node;
1298
+ list.i = list.index;
1299
+ delete list.index;
1300
+ break;
1301
+ case 4 /* NodeTypes.Named */:
1302
+ const named = node;
1303
+ named.k = named.key;
1304
+ delete named.key;
1305
+ break;
1306
+ }
1307
+ delete node.type;
1308
+ }
1309
+ /* eslint-enable @typescript-eslint/no-explicit-any */
1310
+
1311
+ function createCodeGenerator(ast, options) {
1312
+ const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options;
1313
+ const location = options.location !== false;
1314
+ const _context = {
1315
+ filename,
1316
+ code: '',
1317
+ column: 1,
1318
+ line: 1,
1319
+ offset: 0,
1320
+ map: undefined,
1321
+ breakLineCode,
1322
+ needIndent: _needIndent,
1323
+ indentLevel: 0
1324
+ };
1325
+ if (location && ast.loc) {
1326
+ _context.source = ast.loc.source;
1327
+ }
1328
+ const context = () => _context;
1329
+ function push(code, node) {
1330
+ _context.code += code;
1331
+ if (_context.map) {
1332
+ if (node && node.loc && node.loc !== LOCATION_STUB) {
1333
+ addMapping(node.loc.start, getMappingName(node));
1334
+ }
1335
+ advancePositionWithSource(_context, code);
1336
+ }
1337
+ }
1338
+ function _newline(n, withBreakLine = true) {
1339
+ const _breakLineCode = withBreakLine ? breakLineCode : '';
1340
+ push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
1341
+ }
1342
+ function indent(withNewLine = true) {
1343
+ const level = ++_context.indentLevel;
1344
+ withNewLine && _newline(level);
1345
+ }
1346
+ function deindent(withNewLine = true) {
1347
+ const level = --_context.indentLevel;
1348
+ withNewLine && _newline(level);
1349
+ }
1350
+ function newline() {
1351
+ _newline(_context.indentLevel);
1352
+ }
1353
+ const helper = (key) => `_${key}`;
1354
+ const needIndent = () => _context.needIndent;
1355
+ function addMapping(loc, name) {
1356
+ _context.map.addMapping({
1357
+ name,
1358
+ source: _context.filename,
1359
+ original: {
1360
+ line: loc.line,
1361
+ column: loc.column - 1
1362
+ },
1363
+ generated: {
1364
+ line: _context.line,
1365
+ column: _context.column - 1
1366
+ }
1367
+ });
1368
+ }
1369
+ if (location && sourceMap) {
1370
+ _context.map = new sourceMapJs.SourceMapGenerator();
1371
+ _context.map.setSourceContent(filename, _context.source);
1372
+ }
1373
+ return {
1374
+ context,
1375
+ push,
1376
+ indent,
1377
+ deindent,
1378
+ newline,
1379
+ helper,
1380
+ needIndent
1381
+ };
1382
+ }
1383
+ function generateLinkedNode(generator, node) {
1384
+ const { helper } = generator;
1385
+ generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`);
1386
+ generateNode(generator, node.key);
1387
+ if (node.modifier) {
1388
+ generator.push(`, `);
1389
+ generateNode(generator, node.modifier);
1390
+ generator.push(`, _type`);
1391
+ }
1392
+ else {
1393
+ generator.push(`, undefined, _type`);
1394
+ }
1395
+ generator.push(`)`);
1396
+ }
1397
+ function generateMessageNode(generator, node) {
1398
+ const { helper, needIndent } = generator;
1399
+ generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`);
1400
+ generator.indent(needIndent());
1401
+ const length = node.items.length;
1402
+ for (let i = 0; i < length; i++) {
1403
+ generateNode(generator, node.items[i]);
1404
+ if (i === length - 1) {
1405
+ break;
1406
+ }
1407
+ generator.push(', ');
1408
+ }
1409
+ generator.deindent(needIndent());
1410
+ generator.push('])');
1411
+ }
1412
+ function generatePluralNode(generator, node) {
1413
+ const { helper, needIndent } = generator;
1414
+ if (node.cases.length > 1) {
1415
+ generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`);
1416
+ generator.indent(needIndent());
1417
+ const length = node.cases.length;
1418
+ for (let i = 0; i < length; i++) {
1419
+ generateNode(generator, node.cases[i]);
1420
+ if (i === length - 1) {
1421
+ break;
1422
+ }
1423
+ generator.push(', ');
1424
+ }
1425
+ generator.deindent(needIndent());
1426
+ generator.push(`])`);
1427
+ }
1428
+ }
1429
+ function generateResource(generator, node) {
1430
+ if (node.body) {
1431
+ generateNode(generator, node.body);
1432
+ }
1433
+ else {
1434
+ generator.push('null');
1435
+ }
1436
+ }
1437
+ function generateNode(generator, node) {
1438
+ const { helper } = generator;
1439
+ switch (node.type) {
1440
+ case 0 /* NodeTypes.Resource */:
1441
+ generateResource(generator, node);
1442
+ break;
1443
+ case 1 /* NodeTypes.Plural */:
1444
+ generatePluralNode(generator, node);
1445
+ break;
1446
+ case 2 /* NodeTypes.Message */:
1447
+ generateMessageNode(generator, node);
1448
+ break;
1449
+ case 6 /* NodeTypes.Linked */:
1450
+ generateLinkedNode(generator, node);
1451
+ break;
1452
+ case 8 /* NodeTypes.LinkedModifier */:
1453
+ generator.push(JSON.stringify(node.value), node);
1454
+ break;
1455
+ case 7 /* NodeTypes.LinkedKey */:
1456
+ generator.push(JSON.stringify(node.value), node);
1457
+ break;
1458
+ case 5 /* NodeTypes.List */:
1459
+ generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node);
1460
+ break;
1461
+ case 4 /* NodeTypes.Named */:
1462
+ generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node);
1463
+ break;
1464
+ case 9 /* NodeTypes.Literal */:
1465
+ generator.push(JSON.stringify(node.value), node);
1466
+ break;
1467
+ case 3 /* NodeTypes.Text */:
1468
+ generator.push(JSON.stringify(node.value), node);
1469
+ break;
1470
+ }
1471
+ }
1472
+ // generate code from AST
1473
+ const generate = (ast, options = {} // eslint-disable-line
1474
+ ) => {
1475
+ const mode = shared.isString(options.mode) ? options.mode : 'normal';
1476
+ const filename = shared.isString(options.filename)
1477
+ ? options.filename
1478
+ : 'message.intl';
1479
+ const sourceMap = !!options.sourceMap;
1480
+ // prettier-ignore
1481
+ const breakLineCode = options.breakLineCode != null
1482
+ ? options.breakLineCode
1483
+ : mode === 'arrow'
1484
+ ? ';'
1485
+ : '\n';
1486
+ const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
1487
+ const helpers = ast.helpers || [];
1488
+ const generator = createCodeGenerator(ast, {
1489
+ mode,
1490
+ filename,
1491
+ sourceMap,
1492
+ breakLineCode,
1493
+ needIndent
1494
+ });
1495
+ generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
1496
+ generator.indent(needIndent);
1497
+ if (helpers.length > 0) {
1498
+ generator.push(`const { ${shared.join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`);
1499
+ generator.newline();
1500
+ }
1501
+ generator.push(`return `);
1502
+ generateNode(generator, ast);
1503
+ generator.deindent(needIndent);
1504
+ generator.push(`}`);
1505
+ delete ast.helpers;
1506
+ const { code, map } = generator.context();
1507
+ return {
1508
+ ast,
1509
+ code,
1510
+ map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
1511
+ };
1512
+ };
1513
+ function getMappingName(node) {
1514
+ switch (node.type) {
1515
+ case 3 /* NodeTypes.Text */:
1516
+ case 9 /* NodeTypes.Literal */:
1517
+ case 8 /* NodeTypes.LinkedModifier */:
1518
+ case 7 /* NodeTypes.LinkedKey */:
1519
+ return node.value;
1520
+ case 5 /* NodeTypes.List */:
1521
+ return node.index.toString();
1522
+ case 4 /* NodeTypes.Named */:
1523
+ return node.key;
1524
+ default:
1525
+ return undefined;
1526
+ }
1527
+ }
1528
+ function advancePositionWithSource(pos, source, numberOfCharacters = source.length) {
1529
+ let linesCount = 0;
1530
+ let lastNewLinePos = -1;
1531
+ for (let i = 0; i < numberOfCharacters; i++) {
1532
+ if (source.charCodeAt(i) === 10 /* newline char code */) {
1533
+ linesCount++;
1534
+ lastNewLinePos = i;
1535
+ }
1536
+ }
1537
+ pos.offset += numberOfCharacters;
1538
+ pos.line += linesCount;
1539
+ pos.column =
1540
+ lastNewLinePos === -1
1541
+ ? pos.column + numberOfCharacters
1542
+ : numberOfCharacters - lastNewLinePos;
1543
+ return pos;
1414
1544
  }
1415
1545
 
1416
- function baseCompile(source, options = {}) {
1417
- const assignedOptions = shared.assign({}, options);
1418
- // parse source codes
1419
- const parser = createParser(assignedOptions);
1420
- const ast = parser.parse(source);
1421
- // transform ASTs
1422
- transform(ast, assignedOptions);
1423
- // generate javascript codes
1424
- return generate(ast, assignedOptions);
1546
+ function baseCompile(source, options = {}) {
1547
+ const assignedOptions = shared.assign({}, options);
1548
+ const jit = !!assignedOptions.jit;
1549
+ const enalbeMinify = !!assignedOptions.minify;
1550
+ const enambeOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize;
1551
+ // parse source codes
1552
+ const parser = createParser(assignedOptions);
1553
+ const ast = parser.parse(source);
1554
+ if (!jit) {
1555
+ // transform ASTs
1556
+ transform(ast, assignedOptions);
1557
+ // generate javascript codes
1558
+ return generate(ast, assignedOptions);
1559
+ }
1560
+ else {
1561
+ // optimize ASTs
1562
+ enambeOptimize && optimize(ast);
1563
+ // minimize ASTs
1564
+ enalbeMinify && minify(ast);
1565
+ // In JIT mode, no ast transform, no code generation.
1566
+ return { ast, code: '' };
1567
+ }
1425
1568
  }
1426
1569
 
1427
1570
  exports.CompileErrorCodes = CompileErrorCodes;
1428
1571
  exports.ERROR_DOMAIN = ERROR_DOMAIN;
1429
- exports.LocationStub = LocationStub;
1572
+ exports.LOCATION_STUB = LOCATION_STUB;
1430
1573
  exports.baseCompile = baseCompile;
1431
1574
  exports.createCompileError = createCompileError;
1432
1575
  exports.createLocation = createLocation;
1433
1576
  exports.createParser = createParser;
1434
1577
  exports.createPosition = createPosition;
1435
1578
  exports.defaultOnError = defaultOnError;
1579
+ exports.detectHtmlTag = detectHtmlTag;
1436
1580
  exports.errorMessages = errorMessages;