@intlify/message-compiler 11.1.2 → 12.0.0-alpha.2

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,9 +1,9 @@
1
1
  /*!
2
- * message-compiler v11.1.2
3
- * (c) 2025 kazuya kawaguchi
2
+ * message-compiler v12.0.0-alpha.2
3
+ * (c) 2016-present kazuya kawaguchi and contributors
4
4
  * Released under the MIT License.
5
5
  */
6
- import { format, assign, join, isString } from '@intlify/shared';
6
+ import { format, isString, join, assign } from '@intlify/shared';
7
7
 
8
8
  const LOCATION_STUB = {
9
9
  start: { line: 1, column: 1, offset: 0 },
@@ -87,9 +87,318 @@ function defaultOnError(error) {
87
87
  throw error;
88
88
  }
89
89
 
90
- // eslint-disable-next-line no-useless-escape
91
- const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/;
92
- const detectHtmlTag = (source) => RE_HTML_TAG.test(source);
90
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
91
+ /// <reference types="source-map-js" />
92
+ const ERROR_DOMAIN$3 = 'parser';
93
+ function createCodeGenerator(ast, options) {
94
+ const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options;
95
+ const location = options.location !== false;
96
+ const _context = {
97
+ filename,
98
+ code: '',
99
+ column: 1,
100
+ line: 1,
101
+ offset: 0,
102
+ map: undefined,
103
+ breakLineCode,
104
+ needIndent: _needIndent,
105
+ indentLevel: 0
106
+ };
107
+ if (location && ast.loc) {
108
+ _context.source = ast.loc.source;
109
+ }
110
+ const context = () => _context;
111
+ function push(code, node) {
112
+ _context.code += code;
113
+ }
114
+ function _newline(n, withBreakLine = true) {
115
+ const _breakLineCode = withBreakLine ? breakLineCode : '';
116
+ push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
117
+ }
118
+ function indent(withNewLine = true) {
119
+ const level = ++_context.indentLevel;
120
+ withNewLine && _newline(level);
121
+ }
122
+ function deindent(withNewLine = true) {
123
+ const level = --_context.indentLevel;
124
+ withNewLine && _newline(level);
125
+ }
126
+ function newline() {
127
+ _newline(_context.indentLevel);
128
+ }
129
+ const helper = (key) => `_${key}`;
130
+ const needIndent = () => _context.needIndent;
131
+ return {
132
+ context,
133
+ push,
134
+ indent,
135
+ deindent,
136
+ newline,
137
+ helper,
138
+ needIndent
139
+ };
140
+ }
141
+ function generateLinkedNode(generator, node) {
142
+ const { helper } = generator;
143
+ generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`);
144
+ generateNode(generator, node.key);
145
+ if (node.modifier) {
146
+ generator.push(`, `);
147
+ generateNode(generator, node.modifier);
148
+ generator.push(`, _type`);
149
+ }
150
+ else {
151
+ generator.push(`, undefined, _type`);
152
+ }
153
+ generator.push(`)`);
154
+ }
155
+ function generateMessageNode(generator, node) {
156
+ const { helper, needIndent } = generator;
157
+ generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`);
158
+ generator.indent(needIndent());
159
+ const length = node.items.length;
160
+ for (let i = 0; i < length; i++) {
161
+ generateNode(generator, node.items[i]);
162
+ if (i === length - 1) {
163
+ break;
164
+ }
165
+ generator.push(', ');
166
+ }
167
+ generator.deindent(needIndent());
168
+ generator.push('])');
169
+ }
170
+ function generatePluralNode(generator, node) {
171
+ const { helper, needIndent } = generator;
172
+ if (node.cases.length > 1) {
173
+ generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`);
174
+ generator.indent(needIndent());
175
+ const length = node.cases.length;
176
+ for (let i = 0; i < length; i++) {
177
+ generateNode(generator, node.cases[i]);
178
+ if (i === length - 1) {
179
+ break;
180
+ }
181
+ generator.push(', ');
182
+ }
183
+ generator.deindent(needIndent());
184
+ generator.push(`])`);
185
+ }
186
+ }
187
+ function generateResource(generator, node) {
188
+ if (node.body) {
189
+ generateNode(generator, node.body);
190
+ }
191
+ else {
192
+ generator.push('null');
193
+ }
194
+ }
195
+ function generateNode(generator, node) {
196
+ const { helper } = generator;
197
+ switch (node.type) {
198
+ case 0 /* NodeTypes.Resource */:
199
+ generateResource(generator, node);
200
+ break;
201
+ case 1 /* NodeTypes.Plural */:
202
+ generatePluralNode(generator, node);
203
+ break;
204
+ case 2 /* NodeTypes.Message */:
205
+ generateMessageNode(generator, node);
206
+ break;
207
+ case 6 /* NodeTypes.Linked */:
208
+ generateLinkedNode(generator, node);
209
+ break;
210
+ case 8 /* NodeTypes.LinkedModifier */:
211
+ generator.push(JSON.stringify(node.value), node);
212
+ break;
213
+ case 7 /* NodeTypes.LinkedKey */:
214
+ generator.push(JSON.stringify(node.value), node);
215
+ break;
216
+ case 5 /* NodeTypes.List */:
217
+ generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node);
218
+ break;
219
+ case 4 /* NodeTypes.Named */:
220
+ generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node);
221
+ break;
222
+ case 9 /* NodeTypes.Literal */:
223
+ generator.push(JSON.stringify(node.value), node);
224
+ break;
225
+ case 3 /* NodeTypes.Text */:
226
+ generator.push(JSON.stringify(node.value), node);
227
+ break;
228
+ default:
229
+ if ((process.env.NODE_ENV !== 'production')) {
230
+ throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, {
231
+ domain: ERROR_DOMAIN$3,
232
+ args: [node.type]
233
+ });
234
+ }
235
+ }
236
+ }
237
+ // generate code from AST
238
+ const generate = (ast, options = {}) => {
239
+ const mode = isString(options.mode) ? options.mode : 'normal';
240
+ const filename = isString(options.filename)
241
+ ? options.filename
242
+ : 'message.intl';
243
+ const sourceMap = !!options.sourceMap;
244
+ // prettier-ignore
245
+ const breakLineCode = options.breakLineCode != null
246
+ ? options.breakLineCode
247
+ : mode === 'arrow'
248
+ ? ';'
249
+ : '\n';
250
+ const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
251
+ const helpers = ast.helpers || [];
252
+ const generator = createCodeGenerator(ast, {
253
+ mode,
254
+ filename,
255
+ sourceMap,
256
+ breakLineCode,
257
+ needIndent
258
+ });
259
+ generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
260
+ generator.indent(needIndent);
261
+ if (helpers.length > 0) {
262
+ generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`);
263
+ generator.newline();
264
+ }
265
+ generator.push(`return `);
266
+ generateNode(generator, ast);
267
+ generator.deindent(needIndent);
268
+ generator.push(`}`);
269
+ delete ast.helpers;
270
+ const { code, map } = generator.context();
271
+ return {
272
+ ast,
273
+ code,
274
+ map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
275
+ };
276
+ };
277
+
278
+ const ERROR_DOMAIN$2 = 'minifier';
279
+ /* eslint-disable @typescript-eslint/no-explicit-any */
280
+ function mangle(node) {
281
+ node.t = node.type;
282
+ switch (node.type) {
283
+ case 0 /* NodeTypes.Resource */: {
284
+ const resource = node;
285
+ mangle(resource.body);
286
+ resource.b = resource.body;
287
+ delete resource.body;
288
+ break;
289
+ }
290
+ case 1 /* NodeTypes.Plural */: {
291
+ const plural = node;
292
+ const cases = plural.cases;
293
+ for (let i = 0; i < cases.length; i++) {
294
+ mangle(cases[i]);
295
+ }
296
+ plural.c = cases;
297
+ delete plural.cases;
298
+ break;
299
+ }
300
+ case 2 /* NodeTypes.Message */: {
301
+ const message = node;
302
+ const items = message.items;
303
+ for (let i = 0; i < items.length; i++) {
304
+ mangle(items[i]);
305
+ }
306
+ message.i = items;
307
+ delete message.items;
308
+ if (message.static) {
309
+ message.s = message.static;
310
+ delete message.static;
311
+ }
312
+ break;
313
+ }
314
+ case 3 /* NodeTypes.Text */:
315
+ case 9 /* NodeTypes.Literal */:
316
+ case 8 /* NodeTypes.LinkedModifier */:
317
+ case 7 /* NodeTypes.LinkedKey */: {
318
+ const valueNode = node;
319
+ if (valueNode.value) {
320
+ valueNode.v = valueNode.value;
321
+ delete valueNode.value;
322
+ }
323
+ break;
324
+ }
325
+ case 6 /* NodeTypes.Linked */: {
326
+ const linked = node;
327
+ mangle(linked.key);
328
+ linked.k = linked.key;
329
+ delete linked.key;
330
+ if (linked.modifier) {
331
+ mangle(linked.modifier);
332
+ linked.m = linked.modifier;
333
+ delete linked.modifier;
334
+ }
335
+ break;
336
+ }
337
+ case 5 /* NodeTypes.List */: {
338
+ const list = node;
339
+ list.i = list.index;
340
+ delete list.index;
341
+ break;
342
+ }
343
+ case 4 /* NodeTypes.Named */: {
344
+ const named = node;
345
+ named.k = named.key;
346
+ delete named.key;
347
+ break;
348
+ }
349
+ default:
350
+ if ((process.env.NODE_ENV !== 'production')) {
351
+ throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, {
352
+ domain: ERROR_DOMAIN$2,
353
+ args: [node.type]
354
+ });
355
+ }
356
+ }
357
+ delete node.type;
358
+ }
359
+ /* eslint-enable @typescript-eslint/no-explicit-any */
360
+
361
+ function optimize(ast) {
362
+ const body = ast.body;
363
+ if (body.type === 2 /* NodeTypes.Message */) {
364
+ optimizeMessageNode(body);
365
+ }
366
+ else {
367
+ body.cases.forEach(c => optimizeMessageNode(c));
368
+ }
369
+ return ast;
370
+ }
371
+ function optimizeMessageNode(message) {
372
+ if (message.items.length === 1) {
373
+ const item = message.items[0];
374
+ if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
375
+ message.static = item.value;
376
+ delete item.value; // optimization for size
377
+ }
378
+ }
379
+ else {
380
+ const values = [];
381
+ for (let i = 0; i < message.items.length; i++) {
382
+ const item = message.items[i];
383
+ if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) {
384
+ break;
385
+ }
386
+ if (item.value == null) {
387
+ break;
388
+ }
389
+ values.push(item.value);
390
+ }
391
+ if (values.length === message.items.length) {
392
+ message.static = join(values);
393
+ for (let i = 0; i < message.items.length; i++) {
394
+ const item = message.items[i];
395
+ if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
396
+ delete item.value; // optimization for size
397
+ }
398
+ }
399
+ }
400
+ }
401
+ }
93
402
 
94
403
  const CHAR_SP = ' ';
95
404
  const CHAR_CR = '\r';
@@ -169,7 +478,7 @@ function createScanner(str) {
169
478
  const EOF = undefined;
170
479
  const DOT = '.';
171
480
  const LITERAL_DELIMITER = "'";
172
- const ERROR_DOMAIN$3 = 'tokenizer';
481
+ const ERROR_DOMAIN$1 = 'tokenizer';
173
482
  function createTokenizer(source, options = {}) {
174
483
  const location = options.location !== false;
175
484
  const _scnr = createScanner(source);
@@ -199,7 +508,7 @@ function createTokenizer(source, options = {}) {
199
508
  if (onError) {
200
509
  const loc = location ? createLocation(ctx.startLoc, pos) : null;
201
510
  const err = createCompileError(code, loc, {
202
- domain: ERROR_DOMAIN$3,
511
+ domain: ERROR_DOMAIN$1,
203
512
  args
204
513
  });
205
514
  onError(err);
@@ -820,7 +1129,7 @@ function createTokenizer(source, options = {}) {
820
1129
  };
821
1130
  }
822
1131
 
823
- const ERROR_DOMAIN$2 = 'parser';
1132
+ const ERROR_DOMAIN = 'parser';
824
1133
  // Backslash backslash, backslash quote, uHHHH, UHHHHHH.
825
1134
  const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
826
1135
  function fromEscapeSequence(match, codePoint4, codePoint6) {
@@ -852,7 +1161,7 @@ function createParser(options = {}) {
852
1161
  if (onError) {
853
1162
  const loc = location ? createLocation(start, end) : null;
854
1163
  const err = createCompileError(code, loc, {
855
- domain: ERROR_DOMAIN$2,
1164
+ domain: ERROR_DOMAIN,
856
1165
  args
857
1166
  });
858
1167
  onError(err);
@@ -1085,420 +1394,109 @@ function createParser(options = {}) {
1085
1394
  const context = tokenizer.context();
1086
1395
  const { offset, startLoc } = context;
1087
1396
  const msgNode = parseMessage(tokenizer);
1088
- if (context.currentType === 13 /* TokenTypes.EOF */) {
1089
- return msgNode;
1090
- }
1091
- else {
1092
- return parsePlural(tokenizer, offset, startLoc, msgNode);
1093
- }
1094
- }
1095
- function parse(source) {
1096
- const tokenizer = createTokenizer(source, assign({}, options));
1097
- const context = tokenizer.context();
1098
- const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc);
1099
- if (location && node.loc) {
1100
- node.loc.source = source;
1101
- }
1102
- node.body = parseResource(tokenizer);
1103
- if (options.onCacheKey) {
1104
- node.cacheKey = options.onCacheKey(source);
1105
- }
1106
- // assert whether achieved to EOF
1107
- if (context.currentType !== 13 /* TokenTypes.EOF */) {
1108
- emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || '');
1109
- }
1110
- endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1111
- return node;
1112
- }
1113
- return { parse };
1114
- }
1115
- function getTokenCaption(token) {
1116
- if (token.type === 13 /* TokenTypes.EOF */) {
1117
- return 'EOF';
1118
- }
1119
- const name = (token.value || '').replace(/\r?\n/gu, '\\n');
1120
- return name.length > 10 ? name.slice(0, 9) + '…' : name;
1121
- }
1122
-
1123
- function createTransformer(ast, options = {} // eslint-disable-line
1124
- ) {
1125
- const _context = {
1126
- ast,
1127
- helpers: new Set()
1128
- };
1129
- const context = () => _context;
1130
- const helper = (name) => {
1131
- _context.helpers.add(name);
1132
- return name;
1133
- };
1134
- return { context, helper };
1135
- }
1136
- function traverseNodes(nodes, transformer) {
1137
- for (let i = 0; i < nodes.length; i++) {
1138
- traverseNode(nodes[i], transformer);
1139
- }
1140
- }
1141
- function traverseNode(node, transformer) {
1142
- // TODO: if we need pre-hook of transform, should be implemented to here
1143
- switch (node.type) {
1144
- case 1 /* NodeTypes.Plural */:
1145
- traverseNodes(node.cases, transformer);
1146
- transformer.helper("plural" /* HelperNameMap.PLURAL */);
1147
- break;
1148
- case 2 /* NodeTypes.Message */:
1149
- traverseNodes(node.items, transformer);
1150
- break;
1151
- case 6 /* NodeTypes.Linked */: {
1152
- const linked = node;
1153
- traverseNode(linked.key, transformer);
1154
- transformer.helper("linked" /* HelperNameMap.LINKED */);
1155
- transformer.helper("type" /* HelperNameMap.TYPE */);
1156
- break;
1157
- }
1158
- case 5 /* NodeTypes.List */:
1159
- transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
1160
- transformer.helper("list" /* HelperNameMap.LIST */);
1161
- break;
1162
- case 4 /* NodeTypes.Named */:
1163
- transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
1164
- transformer.helper("named" /* HelperNameMap.NAMED */);
1165
- break;
1166
- }
1167
- // TODO: if we need post-hook of transform, should be implemented to here
1168
- }
1169
- // transform AST
1170
- function transform(ast, options = {} // eslint-disable-line
1171
- ) {
1172
- const transformer = createTransformer(ast);
1173
- transformer.helper("normalize" /* HelperNameMap.NORMALIZE */);
1174
- // traverse
1175
- ast.body && traverseNode(ast.body, transformer);
1176
- // set meta information
1177
- const context = transformer.context();
1178
- ast.helpers = Array.from(context.helpers);
1179
- }
1180
-
1181
- function optimize(ast) {
1182
- const body = ast.body;
1183
- if (body.type === 2 /* NodeTypes.Message */) {
1184
- optimizeMessageNode(body);
1185
- }
1186
- else {
1187
- body.cases.forEach(c => optimizeMessageNode(c));
1188
- }
1189
- return ast;
1190
- }
1191
- function optimizeMessageNode(message) {
1192
- if (message.items.length === 1) {
1193
- const item = message.items[0];
1194
- if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
1195
- message.static = item.value;
1196
- delete item.value; // optimization for size
1197
- }
1198
- }
1199
- else {
1200
- const values = [];
1201
- for (let i = 0; i < message.items.length; i++) {
1202
- const item = message.items[i];
1203
- if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) {
1204
- break;
1205
- }
1206
- if (item.value == null) {
1207
- break;
1208
- }
1209
- values.push(item.value);
1210
- }
1211
- if (values.length === message.items.length) {
1212
- message.static = join(values);
1213
- for (let i = 0; i < message.items.length; i++) {
1214
- const item = message.items[i];
1215
- if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) {
1216
- delete item.value; // optimization for size
1217
- }
1218
- }
1219
- }
1220
- }
1221
- }
1222
-
1223
- const ERROR_DOMAIN$1 = 'minifier';
1224
- /* eslint-disable @typescript-eslint/no-explicit-any */
1225
- function minify(node) {
1226
- node.t = node.type;
1227
- switch (node.type) {
1228
- case 0 /* NodeTypes.Resource */: {
1229
- const resource = node;
1230
- minify(resource.body);
1231
- resource.b = resource.body;
1232
- delete resource.body;
1233
- break;
1234
- }
1235
- case 1 /* NodeTypes.Plural */: {
1236
- const plural = node;
1237
- const cases = plural.cases;
1238
- for (let i = 0; i < cases.length; i++) {
1239
- minify(cases[i]);
1240
- }
1241
- plural.c = cases;
1242
- delete plural.cases;
1243
- break;
1244
- }
1245
- case 2 /* NodeTypes.Message */: {
1246
- const message = node;
1247
- const items = message.items;
1248
- for (let i = 0; i < items.length; i++) {
1249
- minify(items[i]);
1250
- }
1251
- message.i = items;
1252
- delete message.items;
1253
- if (message.static) {
1254
- message.s = message.static;
1255
- delete message.static;
1256
- }
1257
- break;
1258
- }
1259
- case 3 /* NodeTypes.Text */:
1260
- case 9 /* NodeTypes.Literal */:
1261
- case 8 /* NodeTypes.LinkedModifier */:
1262
- case 7 /* NodeTypes.LinkedKey */: {
1263
- const valueNode = node;
1264
- if (valueNode.value) {
1265
- valueNode.v = valueNode.value;
1266
- delete valueNode.value;
1267
- }
1268
- break;
1269
- }
1270
- case 6 /* NodeTypes.Linked */: {
1271
- const linked = node;
1272
- minify(linked.key);
1273
- linked.k = linked.key;
1274
- delete linked.key;
1275
- if (linked.modifier) {
1276
- minify(linked.modifier);
1277
- linked.m = linked.modifier;
1278
- delete linked.modifier;
1279
- }
1280
- break;
1397
+ if (context.currentType === 13 /* TokenTypes.EOF */) {
1398
+ return msgNode;
1281
1399
  }
1282
- case 5 /* NodeTypes.List */: {
1283
- const list = node;
1284
- list.i = list.index;
1285
- delete list.index;
1286
- break;
1400
+ else {
1401
+ return parsePlural(tokenizer, offset, startLoc, msgNode);
1287
1402
  }
1288
- case 4 /* NodeTypes.Named */: {
1289
- const named = node;
1290
- named.k = named.key;
1291
- delete named.key;
1292
- break;
1403
+ }
1404
+ function parse(source) {
1405
+ const tokenizer = createTokenizer(source, assign({}, options));
1406
+ const context = tokenizer.context();
1407
+ const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc);
1408
+ if (location && node.loc) {
1409
+ node.loc.source = source;
1293
1410
  }
1294
- default:
1295
- if ((process.env.NODE_ENV !== 'production')) {
1296
- throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, {
1297
- domain: ERROR_DOMAIN$1,
1298
- args: [node.type]
1299
- });
1300
- }
1411
+ node.body = parseResource(tokenizer);
1412
+ if (options.onCacheKey) {
1413
+ node.cacheKey = options.onCacheKey(source);
1414
+ }
1415
+ // assert whether achieved to EOF
1416
+ if (context.currentType !== 13 /* TokenTypes.EOF */) {
1417
+ emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || '');
1418
+ }
1419
+ endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1420
+ return node;
1301
1421
  }
1302
- delete node.type;
1422
+ return { parse };
1423
+ }
1424
+ function getTokenCaption(token) {
1425
+ if (token.type === 13 /* TokenTypes.EOF */) {
1426
+ return 'EOF';
1427
+ }
1428
+ const name = (token.value || '').replace(/\r?\n/gu, '\\n');
1429
+ return name.length > 10 ? name.slice(0, 9) + '…' : name;
1303
1430
  }
1304
- /* eslint-enable @typescript-eslint/no-explicit-any */
1305
1431
 
1306
- // eslint-disable-next-line @typescript-eslint/triple-slash-reference
1307
- /// <reference types="source-map-js" />
1308
- const ERROR_DOMAIN = 'parser';
1309
- function createCodeGenerator(ast, options) {
1310
- const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options;
1311
- const location = options.location !== false;
1432
+ function createTransformer(ast, options = {} // eslint-disable-line
1433
+ ) {
1312
1434
  const _context = {
1313
- filename,
1314
- code: '',
1315
- column: 1,
1316
- line: 1,
1317
- offset: 0,
1318
- map: undefined,
1319
- breakLineCode,
1320
- needIndent: _needIndent,
1321
- indentLevel: 0
1435
+ ast,
1436
+ helpers: new Set()
1322
1437
  };
1323
- if (location && ast.loc) {
1324
- _context.source = ast.loc.source;
1325
- }
1326
1438
  const context = () => _context;
1327
- function push(code, node) {
1328
- _context.code += code;
1329
- }
1330
- function _newline(n, withBreakLine = true) {
1331
- const _breakLineCode = withBreakLine ? breakLineCode : '';
1332
- push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
1333
- }
1334
- function indent(withNewLine = true) {
1335
- const level = ++_context.indentLevel;
1336
- withNewLine && _newline(level);
1337
- }
1338
- function deindent(withNewLine = true) {
1339
- const level = --_context.indentLevel;
1340
- withNewLine && _newline(level);
1341
- }
1342
- function newline() {
1343
- _newline(_context.indentLevel);
1344
- }
1345
- const helper = (key) => `_${key}`;
1346
- const needIndent = () => _context.needIndent;
1347
- return {
1348
- context,
1349
- push,
1350
- indent,
1351
- deindent,
1352
- newline,
1353
- helper,
1354
- needIndent
1439
+ const helper = (name) => {
1440
+ _context.helpers.add(name);
1441
+ return name;
1355
1442
  };
1443
+ return { context, helper };
1356
1444
  }
1357
- function generateLinkedNode(generator, node) {
1358
- const { helper } = generator;
1359
- generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`);
1360
- generateNode(generator, node.key);
1361
- if (node.modifier) {
1362
- generator.push(`, `);
1363
- generateNode(generator, node.modifier);
1364
- generator.push(`, _type`);
1365
- }
1366
- else {
1367
- generator.push(`, undefined, _type`);
1368
- }
1369
- generator.push(`)`);
1370
- }
1371
- function generateMessageNode(generator, node) {
1372
- const { helper, needIndent } = generator;
1373
- generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`);
1374
- generator.indent(needIndent());
1375
- const length = node.items.length;
1376
- for (let i = 0; i < length; i++) {
1377
- generateNode(generator, node.items[i]);
1378
- if (i === length - 1) {
1379
- break;
1380
- }
1381
- generator.push(', ');
1382
- }
1383
- generator.deindent(needIndent());
1384
- generator.push('])');
1385
- }
1386
- function generatePluralNode(generator, node) {
1387
- const { helper, needIndent } = generator;
1388
- if (node.cases.length > 1) {
1389
- generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`);
1390
- generator.indent(needIndent());
1391
- const length = node.cases.length;
1392
- for (let i = 0; i < length; i++) {
1393
- generateNode(generator, node.cases[i]);
1394
- if (i === length - 1) {
1395
- break;
1396
- }
1397
- generator.push(', ');
1398
- }
1399
- generator.deindent(needIndent());
1400
- generator.push(`])`);
1401
- }
1402
- }
1403
- function generateResource(generator, node) {
1404
- if (node.body) {
1405
- generateNode(generator, node.body);
1406
- }
1407
- else {
1408
- generator.push('null');
1445
+ function traverseNodes(nodes, transformer) {
1446
+ for (let i = 0; i < nodes.length; i++) {
1447
+ traverseNode(nodes[i], transformer);
1409
1448
  }
1410
1449
  }
1411
- function generateNode(generator, node) {
1412
- const { helper } = generator;
1450
+ function traverseNode(node, transformer) {
1451
+ // TODO: if we need pre-hook of transform, should be implemented to here
1413
1452
  switch (node.type) {
1414
- case 0 /* NodeTypes.Resource */:
1415
- generateResource(generator, node);
1416
- break;
1417
1453
  case 1 /* NodeTypes.Plural */:
1418
- generatePluralNode(generator, node);
1454
+ traverseNodes(node.cases, transformer);
1455
+ transformer.helper("plural" /* HelperNameMap.PLURAL */);
1419
1456
  break;
1420
1457
  case 2 /* NodeTypes.Message */:
1421
- generateMessageNode(generator, node);
1422
- break;
1423
- case 6 /* NodeTypes.Linked */:
1424
- generateLinkedNode(generator, node);
1425
- break;
1426
- case 8 /* NodeTypes.LinkedModifier */:
1427
- generator.push(JSON.stringify(node.value), node);
1458
+ traverseNodes(node.items, transformer);
1428
1459
  break;
1429
- case 7 /* NodeTypes.LinkedKey */:
1430
- generator.push(JSON.stringify(node.value), node);
1460
+ case 6 /* NodeTypes.Linked */: {
1461
+ const linked = node;
1462
+ traverseNode(linked.key, transformer);
1463
+ transformer.helper("linked" /* HelperNameMap.LINKED */);
1464
+ transformer.helper("type" /* HelperNameMap.TYPE */);
1431
1465
  break;
1466
+ }
1432
1467
  case 5 /* NodeTypes.List */:
1433
- generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node);
1468
+ transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
1469
+ transformer.helper("list" /* HelperNameMap.LIST */);
1434
1470
  break;
1435
1471
  case 4 /* NodeTypes.Named */:
1436
- generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node);
1437
- break;
1438
- case 9 /* NodeTypes.Literal */:
1439
- generator.push(JSON.stringify(node.value), node);
1440
- break;
1441
- case 3 /* NodeTypes.Text */:
1442
- generator.push(JSON.stringify(node.value), node);
1472
+ transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */);
1473
+ transformer.helper("named" /* HelperNameMap.NAMED */);
1443
1474
  break;
1444
- default:
1445
- if ((process.env.NODE_ENV !== 'production')) {
1446
- throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, {
1447
- domain: ERROR_DOMAIN,
1448
- args: [node.type]
1449
- });
1450
- }
1451
1475
  }
1476
+ // TODO: if we need post-hook of transform, should be implemented to here
1477
+ }
1478
+ // transform AST
1479
+ function transform(ast, options = {} // eslint-disable-line
1480
+ ) {
1481
+ const transformer = createTransformer(ast);
1482
+ transformer.helper("normalize" /* HelperNameMap.NORMALIZE */);
1483
+ // traverse
1484
+ ast.body && traverseNode(ast.body, transformer);
1485
+ // set meta information
1486
+ const context = transformer.context();
1487
+ ast.helpers = Array.from(context.helpers);
1452
1488
  }
1453
- // generate code from AST
1454
- const generate = (ast, options = {}) => {
1455
- const mode = isString(options.mode) ? options.mode : 'normal';
1456
- const filename = isString(options.filename)
1457
- ? options.filename
1458
- : 'message.intl';
1459
- const sourceMap = !!options.sourceMap;
1460
- // prettier-ignore
1461
- const breakLineCode = options.breakLineCode != null
1462
- ? options.breakLineCode
1463
- : mode === 'arrow'
1464
- ? ';'
1465
- : '\n';
1466
- const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
1467
- const helpers = ast.helpers || [];
1468
- const generator = createCodeGenerator(ast, {
1469
- mode,
1470
- filename,
1471
- sourceMap,
1472
- breakLineCode,
1473
- needIndent
1474
- });
1475
- generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
1476
- generator.indent(needIndent);
1477
- if (helpers.length > 0) {
1478
- generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`);
1479
- generator.newline();
1480
- }
1481
- generator.push(`return `);
1482
- generateNode(generator, ast);
1483
- generator.deindent(needIndent);
1484
- generator.push(`}`);
1485
- delete ast.helpers;
1486
- const { code, map } = generator.context();
1487
- return {
1488
- ast,
1489
- code,
1490
- map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
1491
- };
1492
- };
1493
1489
 
1494
1490
  function baseCompile(source, options = {}) {
1495
1491
  const assignedOptions = assign({}, options);
1496
1492
  const jit = !!assignedOptions.jit;
1497
- const enalbeMinify = !!assignedOptions.minify;
1498
- const enambeOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize;
1493
+ const enableMangle = !!assignedOptions.mangle;
1494
+ const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize;
1499
1495
  // parse source codes
1500
1496
  const parser = createParser(assignedOptions);
1501
1497
  const ast = parser.parse(source);
1498
+ // TODO:
1499
+ // With the introduction of Jit compilation, code generation is no longer necessary. This function may no longer be needed since tree-shaking is not possible.
1502
1500
  if (!jit) {
1503
1501
  // transform ASTs
1504
1502
  transform(ast, assignedOptions);
@@ -1507,12 +1505,16 @@ function baseCompile(source, options = {}) {
1507
1505
  }
1508
1506
  else {
1509
1507
  // optimize ASTs
1510
- enambeOptimize && optimize(ast);
1508
+ enableOptimize && optimize(ast);
1511
1509
  // minimize ASTs
1512
- enalbeMinify && minify(ast);
1510
+ enableMangle && mangle(ast);
1513
1511
  // In JIT mode, no ast transform, no code generation.
1514
1512
  return { ast, code: '' };
1515
1513
  }
1516
1514
  }
1517
1515
 
1518
- export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN$2 as ERROR_DOMAIN, LOCATION_STUB, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages };
1516
+ // eslint-disable-next-line no-useless-escape
1517
+ const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/;
1518
+ const detectHtmlTag = (source) => RE_HTML_TAG.test(source);
1519
+
1520
+ export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, LOCATION_STUB, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize };