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