i18next-cli 1.54.2 → 1.55.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.
- package/dist/cjs/cli.js +66 -2
- package/dist/cjs/extractor/core/ast-visitors.js +11 -1
- package/dist/cjs/extractor/core/extractor.js +1 -1
- package/dist/cjs/extractor/parsers/expression-resolver.js +96 -11
- package/dist/esm/cli.js +66 -2
- package/dist/esm/extractor/core/ast-visitors.js +11 -1
- package/dist/esm/extractor/core/extractor.js +1 -1
- package/dist/esm/extractor/parsers/expression-resolver.js +96 -11
- package/package.json +1 -1
- package/types/cli.d.ts.map +1 -1
- package/types/extractor/core/ast-visitors.d.ts.map +1 -1
- package/types/extractor/core/extractor.d.ts +1 -0
- package/types/extractor/core/extractor.d.ts.map +1 -1
- package/types/extractor/parsers/expression-resolver.d.ts +11 -0
- package/types/extractor/parsers/expression-resolver.d.ts.map +1 -1
package/dist/cjs/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ var heuristicConfig = require('./heuristic-config.js');
|
|
|
11
11
|
var extractor = require('./extractor/core/extractor.js');
|
|
12
12
|
require('./extractor/parsers/jsx-parser.js');
|
|
13
13
|
require('node:path');
|
|
14
|
+
var nestedObject = require('./utils/nested-object.js');
|
|
14
15
|
require('node:fs/promises');
|
|
15
16
|
require('jiti');
|
|
16
17
|
require('@croct/json5-parser');
|
|
@@ -31,7 +32,7 @@ const program = new commander.Command();
|
|
|
31
32
|
program
|
|
32
33
|
.name('i18next-cli')
|
|
33
34
|
.description('A unified, high-performance i18next CLI.')
|
|
34
|
-
.version('1.
|
|
35
|
+
.version('1.55.0'); // This string is replaced with the actual version at build time by rollup
|
|
35
36
|
// new: global config override option
|
|
36
37
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
37
38
|
program
|
|
@@ -51,7 +52,7 @@ program
|
|
|
51
52
|
const runExtract = async () => {
|
|
52
53
|
// --sync-all implies sync-primary behavior
|
|
53
54
|
const syncPrimary = !!options.syncPrimary || !!options.syncAll;
|
|
54
|
-
const { anyFileUpdated, hasErrors } = await extractor.runExtractor(config$1, {
|
|
55
|
+
const { anyFileUpdated, hasErrors, results } = await extractor.runExtractor(config$1, {
|
|
55
56
|
isWatchMode: !!options.watch,
|
|
56
57
|
isDryRun: !!options.dryRun,
|
|
57
58
|
syncPrimaryWithDefaults: syncPrimary,
|
|
@@ -65,6 +66,7 @@ program
|
|
|
65
66
|
}
|
|
66
67
|
else if (options.ci && anyFileUpdated) {
|
|
67
68
|
console.error('❌ Some files were updated. This should not happen in CI mode.');
|
|
69
|
+
printCiDiff(results, config$1);
|
|
68
70
|
process.exit(1);
|
|
69
71
|
}
|
|
70
72
|
if (hasErrors && !options.watch) {
|
|
@@ -328,5 +330,67 @@ const expandGlobs = async (patterns = []) => {
|
|
|
328
330
|
const sets = await Promise.all(arr.map(p => glob.glob(p || '', { nodir: true })));
|
|
329
331
|
return Array.from(new Set(sets.flat()));
|
|
330
332
|
};
|
|
333
|
+
function printCiDiff(results, config) {
|
|
334
|
+
const rawSep = config.extract.keySeparator;
|
|
335
|
+
const keySeparator = rawSep === false ? false : (rawSep ?? '.');
|
|
336
|
+
for (const result of results) {
|
|
337
|
+
if (!result.updated)
|
|
338
|
+
continue;
|
|
339
|
+
const existing = result.existingTranslations || {};
|
|
340
|
+
const next = result.newTranslations || {};
|
|
341
|
+
const oldKeys = new Set(nestedObject.getNestedKeys(existing, keySeparator));
|
|
342
|
+
const newKeys = new Set(nestedObject.getNestedKeys(next, keySeparator));
|
|
343
|
+
const added = [];
|
|
344
|
+
const removed = [];
|
|
345
|
+
const changed = [];
|
|
346
|
+
for (const k of newKeys) {
|
|
347
|
+
if (!oldKeys.has(k)) {
|
|
348
|
+
added.push(k);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
const oldVal = nestedObject.getNestedValue(existing, k, keySeparator);
|
|
352
|
+
const newVal = nestedObject.getNestedValue(next, k, keySeparator);
|
|
353
|
+
if (oldVal !== newVal)
|
|
354
|
+
changed.push(k);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
for (const k of oldKeys) {
|
|
358
|
+
if (!newKeys.has(k))
|
|
359
|
+
removed.push(k);
|
|
360
|
+
}
|
|
361
|
+
const nsLabel = result.namespace
|
|
362
|
+
? ` [${result.locale}/${result.namespace}]`
|
|
363
|
+
: ` [${result.locale}]`;
|
|
364
|
+
console.error(`\n ${result.path}${nsLabel}`);
|
|
365
|
+
if (added.length === 0 && removed.length === 0 && changed.length === 0) {
|
|
366
|
+
console.error(' (no key differences — only formatting or ordering changes)');
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
added.sort();
|
|
370
|
+
removed.sort();
|
|
371
|
+
changed.sort();
|
|
372
|
+
for (const k of added) {
|
|
373
|
+
const v = nestedObject.getNestedValue(next, k, keySeparator);
|
|
374
|
+
console.error(node_util.styleText('green', ` + ${k}: ${formatCiDiffValue(v)}`));
|
|
375
|
+
}
|
|
376
|
+
for (const k of removed) {
|
|
377
|
+
const v = nestedObject.getNestedValue(existing, k, keySeparator);
|
|
378
|
+
console.error(node_util.styleText('red', ` - ${k}: ${formatCiDiffValue(v)}`));
|
|
379
|
+
}
|
|
380
|
+
for (const k of changed) {
|
|
381
|
+
const oldV = nestedObject.getNestedValue(existing, k, keySeparator);
|
|
382
|
+
const newV = nestedObject.getNestedValue(next, k, keySeparator);
|
|
383
|
+
console.error(node_util.styleText('yellow', ` ~ ${k}: ${formatCiDiffValue(oldV)} → ${formatCiDiffValue(newV)}`));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function formatCiDiffValue(value) {
|
|
388
|
+
try {
|
|
389
|
+
return JSON.stringify(value);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return String(value);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
331
395
|
|
|
332
396
|
exports.program = program;
|
|
@@ -96,6 +96,16 @@ class ASTVisitors {
|
|
|
96
96
|
this.scopeManager.handleVariableDeclarator(node);
|
|
97
97
|
this.expressionResolver.captureVariableDeclarator(node);
|
|
98
98
|
break;
|
|
99
|
+
case 'TSEnumDeclaration':
|
|
100
|
+
case 'TsEnumDeclaration':
|
|
101
|
+
case 'TsEnumDecl':
|
|
102
|
+
// Enums → ExpressionResolver.sharedEnumTable. Needed in pre-scan so
|
|
103
|
+
// that function bodies referencing enum members (e.g. `return
|
|
104
|
+
// OrganizationType.ROUTING`) can be resolved by the body-inference
|
|
105
|
+
// branch of captureFunctionDeclaration when we hit the function later
|
|
106
|
+
// in the same file.
|
|
107
|
+
this.expressionResolver.captureEnumDeclaration(node);
|
|
108
|
+
break;
|
|
99
109
|
case 'TsTypeAliasDeclaration':
|
|
100
110
|
case 'TSTypeAliasDeclaration':
|
|
101
111
|
case 'TsTypeAliasDecl':
|
|
@@ -104,7 +114,7 @@ class ASTVisitors {
|
|
|
104
114
|
break;
|
|
105
115
|
case 'FunctionDeclaration':
|
|
106
116
|
case 'FnDecl':
|
|
107
|
-
// Return-type annotations for t(fn()) patterns
|
|
117
|
+
// Return-type annotations or inferred return values for t(fn()) patterns
|
|
108
118
|
this.expressionResolver.captureFunctionDeclaration(node);
|
|
109
119
|
break;
|
|
110
120
|
}
|
|
@@ -99,7 +99,7 @@ async function runExtractor(config, options = {}) {
|
|
|
99
99
|
// always show the funnel regardless of cooldown.
|
|
100
100
|
if (anyFileUpdated && !options.isDryRun && !options.quiet)
|
|
101
101
|
await printLocizeFunnel(options.logger, anyNewFile);
|
|
102
|
-
return { anyFileUpdated, hasErrors: fileErrors.length > 0 };
|
|
102
|
+
return { anyFileUpdated, hasErrors: fileErrors.length > 0, results };
|
|
103
103
|
}
|
|
104
104
|
catch (error) {
|
|
105
105
|
spinner.fail(node_util.styleText('red', 'Extraction failed.'));
|
|
@@ -18,6 +18,11 @@ class ExpressionResolver {
|
|
|
18
18
|
// Shared (cross-file) table for type aliases — populated alongside typeAliasTable.
|
|
19
19
|
// Persists across resetFileSymbols() so exported type aliases are visible to importers.
|
|
20
20
|
sharedTypeAliasTable = new Map();
|
|
21
|
+
// Shared (cross-file) table for function return-value sets. Populated from
|
|
22
|
+
// both explicit return-type annotations and body-inferred return values so
|
|
23
|
+
// that `t(fn())` / `const x = fn(); t(\`...${x}...\`)` work across files.
|
|
24
|
+
// Persists across resetFileSymbols() just like the other shared tables.
|
|
25
|
+
sharedFunctionReturnTable = new Map();
|
|
21
26
|
// Temporary per-scope variable overrides, used to inject .map() / .forEach()
|
|
22
27
|
// callback parameters while the callback body is being walked.
|
|
23
28
|
temporaryVariables = new Map();
|
|
@@ -168,15 +173,23 @@ class ExpressionResolver {
|
|
|
168
173
|
return;
|
|
169
174
|
}
|
|
170
175
|
// pattern 3 (arrow function variant):
|
|
171
|
-
// `const fn = (): 'a' | 'b' => ...` — capture the explicit return type annotation
|
|
176
|
+
// `const fn = (): 'a' | 'b' => ...` — capture the explicit return type annotation,
|
|
177
|
+
// OR fall back to walking the body's return expressions / expression body
|
|
178
|
+
// when no annotation is present (mirrors TS's own return-type inference).
|
|
172
179
|
if (unwrappedInit.type === 'ArrowFunctionExpression' || unwrappedInit.type === 'FunctionExpression') {
|
|
180
|
+
let returnVals = [];
|
|
173
181
|
const rawReturnType = unwrappedInit.returnType ?? unwrappedInit.typeAnnotation;
|
|
174
182
|
if (rawReturnType) {
|
|
183
|
+
// Explicit annotation — trust it even when it resolves to [].
|
|
175
184
|
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
185
|
+
returnVals = this.resolvePossibleStringValuesFromType(tsType);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
returnVals = this.inferReturnValuesFromFunctionBody(unwrappedInit);
|
|
189
|
+
}
|
|
190
|
+
if (returnVals.length > 0) {
|
|
191
|
+
this.variableTable.set(name, returnVals);
|
|
192
|
+
this.sharedFunctionReturnTable.set(name, returnVals);
|
|
180
193
|
}
|
|
181
194
|
}
|
|
182
195
|
}
|
|
@@ -231,19 +244,85 @@ class ExpressionResolver {
|
|
|
231
244
|
// or directly in `.returnType` (FunctionExpression / ArrowFunctionExpression).
|
|
232
245
|
const fn = node.function ?? node;
|
|
233
246
|
const rawReturnType = fn.returnType ?? fn.typeAnnotation;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
247
|
+
let vals = [];
|
|
248
|
+
if (rawReturnType) {
|
|
249
|
+
// Unwrap TsTypeAnnotation wrapper if present. Explicit annotations are
|
|
250
|
+
// authoritative: if the author declared the return type we trust it,
|
|
251
|
+
// even when it resolves to [] (e.g. plain `string`). Falling back to
|
|
252
|
+
// body inference in that case would invent keys the author deliberately
|
|
253
|
+
// opted out of.
|
|
254
|
+
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
255
|
+
vals = this.resolvePossibleStringValuesFromType(tsType);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// No annotation — infer from body. Mirrors TS's own return-type
|
|
259
|
+
// inference for functions like:
|
|
260
|
+
// function getCurrentAppType() {
|
|
261
|
+
// if (...) return OrganizationType.ROUTING;
|
|
262
|
+
// if (...) return OrganizationType.CONTRACTOR;
|
|
263
|
+
// }
|
|
264
|
+
vals = this.inferReturnValuesFromFunctionBody(fn);
|
|
265
|
+
}
|
|
239
266
|
if (vals.length > 0) {
|
|
240
267
|
this.variableTable.set(name, vals);
|
|
268
|
+
this.sharedFunctionReturnTable.set(name, vals);
|
|
241
269
|
}
|
|
242
270
|
}
|
|
243
271
|
catch {
|
|
244
272
|
// noop
|
|
245
273
|
}
|
|
246
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Walk a function body's ReturnStatements and union the statically-resolvable
|
|
277
|
+
* string values of their argument expressions. Does NOT descend into nested
|
|
278
|
+
* function declarations (their returns belong to the inner function, not us).
|
|
279
|
+
*
|
|
280
|
+
* This is how we mirror TypeScript's implicit return-type inference for the
|
|
281
|
+
* purpose of extracting translation keys — we don't need exhaustiveness, just
|
|
282
|
+
* the set of string values any return statement could produce.
|
|
283
|
+
*/
|
|
284
|
+
inferReturnValuesFromFunctionBody(fn) {
|
|
285
|
+
const body = fn?.body;
|
|
286
|
+
if (!body)
|
|
287
|
+
return [];
|
|
288
|
+
const collected = [];
|
|
289
|
+
const visit = (n) => {
|
|
290
|
+
if (!n || typeof n !== 'object')
|
|
291
|
+
return;
|
|
292
|
+
// Don't descend into nested function bodies — their returns aren't ours.
|
|
293
|
+
if (n !== body && (n.type === 'FunctionDeclaration' ||
|
|
294
|
+
n.type === 'FunctionExpression' ||
|
|
295
|
+
n.type === 'ArrowFunctionExpression'))
|
|
296
|
+
return;
|
|
297
|
+
if (n.type === 'ReturnStatement' && n.argument) {
|
|
298
|
+
const vals = this.resolvePossibleStringValuesFromExpression(n.argument);
|
|
299
|
+
if (vals.length > 0)
|
|
300
|
+
collected.push(...vals);
|
|
301
|
+
}
|
|
302
|
+
for (const key of Object.keys(n)) {
|
|
303
|
+
const child = n[key];
|
|
304
|
+
if (Array.isArray(child)) {
|
|
305
|
+
for (const item of child) {
|
|
306
|
+
if (item && typeof item === 'object')
|
|
307
|
+
visit(item);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (child && typeof child === 'object' && typeof child.type === 'string') {
|
|
311
|
+
visit(child);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
// Arrow functions with an expression body (no BlockStatement) — `() => expr` —
|
|
316
|
+
// have their return expression directly as `body`.
|
|
317
|
+
if (body.type !== 'BlockStatement') {
|
|
318
|
+
const vals = this.resolvePossibleStringValuesFromExpression(body);
|
|
319
|
+
if (vals.length > 0)
|
|
320
|
+
return Array.from(new Set(vals));
|
|
321
|
+
return [];
|
|
322
|
+
}
|
|
323
|
+
visit(body);
|
|
324
|
+
return Array.from(new Set(collected));
|
|
325
|
+
}
|
|
247
326
|
/**
|
|
248
327
|
* Extract a raw TsType node from an identifier's type annotation.
|
|
249
328
|
* SWC may wrap it in a `TsTypeAnnotation` node — this unwraps it.
|
|
@@ -503,7 +582,10 @@ class ExpressionResolver {
|
|
|
503
582
|
catch { }
|
|
504
583
|
}
|
|
505
584
|
// pattern 3:
|
|
506
|
-
// `t(fn())` — resolve to the function's known return-
|
|
585
|
+
// `t(fn())` — resolve to the function's known return-value set (either
|
|
586
|
+
// from an explicit annotation or inferred from the function body). Check
|
|
587
|
+
// the per-file variable table first (same-file capture) and fall back to
|
|
588
|
+
// the shared cross-file table populated during pre-scan.
|
|
507
589
|
if (expression.type === 'CallExpression') {
|
|
508
590
|
try {
|
|
509
591
|
const callee = expression.callee;
|
|
@@ -511,6 +593,9 @@ class ExpressionResolver {
|
|
|
511
593
|
const v = this.variableTable.get(callee.value);
|
|
512
594
|
if (Array.isArray(v) && v.length > 0)
|
|
513
595
|
return v;
|
|
596
|
+
const sv = this.sharedFunctionReturnTable.get(callee.value);
|
|
597
|
+
if (sv && sv.length > 0)
|
|
598
|
+
return sv;
|
|
514
599
|
}
|
|
515
600
|
}
|
|
516
601
|
catch { }
|
package/dist/esm/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { detectConfig } from './heuristic-config.js';
|
|
|
9
9
|
import { runExtractor } from './extractor/core/extractor.js';
|
|
10
10
|
import './extractor/parsers/jsx-parser.js';
|
|
11
11
|
import 'node:path';
|
|
12
|
+
import { getNestedKeys, getNestedValue } from './utils/nested-object.js';
|
|
12
13
|
import 'node:fs/promises';
|
|
13
14
|
import 'jiti';
|
|
14
15
|
import '@croct/json5-parser';
|
|
@@ -29,7 +30,7 @@ const program = new Command();
|
|
|
29
30
|
program
|
|
30
31
|
.name('i18next-cli')
|
|
31
32
|
.description('A unified, high-performance i18next CLI.')
|
|
32
|
-
.version('1.
|
|
33
|
+
.version('1.55.0'); // This string is replaced with the actual version at build time by rollup
|
|
33
34
|
// new: global config override option
|
|
34
35
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
35
36
|
program
|
|
@@ -49,7 +50,7 @@ program
|
|
|
49
50
|
const runExtract = async () => {
|
|
50
51
|
// --sync-all implies sync-primary behavior
|
|
51
52
|
const syncPrimary = !!options.syncPrimary || !!options.syncAll;
|
|
52
|
-
const { anyFileUpdated, hasErrors } = await runExtractor(config, {
|
|
53
|
+
const { anyFileUpdated, hasErrors, results } = await runExtractor(config, {
|
|
53
54
|
isWatchMode: !!options.watch,
|
|
54
55
|
isDryRun: !!options.dryRun,
|
|
55
56
|
syncPrimaryWithDefaults: syncPrimary,
|
|
@@ -63,6 +64,7 @@ program
|
|
|
63
64
|
}
|
|
64
65
|
else if (options.ci && anyFileUpdated) {
|
|
65
66
|
console.error('❌ Some files were updated. This should not happen in CI mode.');
|
|
67
|
+
printCiDiff(results, config);
|
|
66
68
|
process.exit(1);
|
|
67
69
|
}
|
|
68
70
|
if (hasErrors && !options.watch) {
|
|
@@ -326,5 +328,67 @@ const expandGlobs = async (patterns = []) => {
|
|
|
326
328
|
const sets = await Promise.all(arr.map(p => glob(p || '', { nodir: true })));
|
|
327
329
|
return Array.from(new Set(sets.flat()));
|
|
328
330
|
};
|
|
331
|
+
function printCiDiff(results, config) {
|
|
332
|
+
const rawSep = config.extract.keySeparator;
|
|
333
|
+
const keySeparator = rawSep === false ? false : (rawSep ?? '.');
|
|
334
|
+
for (const result of results) {
|
|
335
|
+
if (!result.updated)
|
|
336
|
+
continue;
|
|
337
|
+
const existing = result.existingTranslations || {};
|
|
338
|
+
const next = result.newTranslations || {};
|
|
339
|
+
const oldKeys = new Set(getNestedKeys(existing, keySeparator));
|
|
340
|
+
const newKeys = new Set(getNestedKeys(next, keySeparator));
|
|
341
|
+
const added = [];
|
|
342
|
+
const removed = [];
|
|
343
|
+
const changed = [];
|
|
344
|
+
for (const k of newKeys) {
|
|
345
|
+
if (!oldKeys.has(k)) {
|
|
346
|
+
added.push(k);
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
const oldVal = getNestedValue(existing, k, keySeparator);
|
|
350
|
+
const newVal = getNestedValue(next, k, keySeparator);
|
|
351
|
+
if (oldVal !== newVal)
|
|
352
|
+
changed.push(k);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
for (const k of oldKeys) {
|
|
356
|
+
if (!newKeys.has(k))
|
|
357
|
+
removed.push(k);
|
|
358
|
+
}
|
|
359
|
+
const nsLabel = result.namespace
|
|
360
|
+
? ` [${result.locale}/${result.namespace}]`
|
|
361
|
+
: ` [${result.locale}]`;
|
|
362
|
+
console.error(`\n ${result.path}${nsLabel}`);
|
|
363
|
+
if (added.length === 0 && removed.length === 0 && changed.length === 0) {
|
|
364
|
+
console.error(' (no key differences — only formatting or ordering changes)');
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
added.sort();
|
|
368
|
+
removed.sort();
|
|
369
|
+
changed.sort();
|
|
370
|
+
for (const k of added) {
|
|
371
|
+
const v = getNestedValue(next, k, keySeparator);
|
|
372
|
+
console.error(styleText('green', ` + ${k}: ${formatCiDiffValue(v)}`));
|
|
373
|
+
}
|
|
374
|
+
for (const k of removed) {
|
|
375
|
+
const v = getNestedValue(existing, k, keySeparator);
|
|
376
|
+
console.error(styleText('red', ` - ${k}: ${formatCiDiffValue(v)}`));
|
|
377
|
+
}
|
|
378
|
+
for (const k of changed) {
|
|
379
|
+
const oldV = getNestedValue(existing, k, keySeparator);
|
|
380
|
+
const newV = getNestedValue(next, k, keySeparator);
|
|
381
|
+
console.error(styleText('yellow', ` ~ ${k}: ${formatCiDiffValue(oldV)} → ${formatCiDiffValue(newV)}`));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function formatCiDiffValue(value) {
|
|
386
|
+
try {
|
|
387
|
+
return JSON.stringify(value);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
return String(value);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
329
393
|
|
|
330
394
|
export { program };
|
|
@@ -94,6 +94,16 @@ class ASTVisitors {
|
|
|
94
94
|
this.scopeManager.handleVariableDeclarator(node);
|
|
95
95
|
this.expressionResolver.captureVariableDeclarator(node);
|
|
96
96
|
break;
|
|
97
|
+
case 'TSEnumDeclaration':
|
|
98
|
+
case 'TsEnumDeclaration':
|
|
99
|
+
case 'TsEnumDecl':
|
|
100
|
+
// Enums → ExpressionResolver.sharedEnumTable. Needed in pre-scan so
|
|
101
|
+
// that function bodies referencing enum members (e.g. `return
|
|
102
|
+
// OrganizationType.ROUTING`) can be resolved by the body-inference
|
|
103
|
+
// branch of captureFunctionDeclaration when we hit the function later
|
|
104
|
+
// in the same file.
|
|
105
|
+
this.expressionResolver.captureEnumDeclaration(node);
|
|
106
|
+
break;
|
|
97
107
|
case 'TsTypeAliasDeclaration':
|
|
98
108
|
case 'TSTypeAliasDeclaration':
|
|
99
109
|
case 'TsTypeAliasDecl':
|
|
@@ -102,7 +112,7 @@ class ASTVisitors {
|
|
|
102
112
|
break;
|
|
103
113
|
case 'FunctionDeclaration':
|
|
104
114
|
case 'FnDecl':
|
|
105
|
-
// Return-type annotations for t(fn()) patterns
|
|
115
|
+
// Return-type annotations or inferred return values for t(fn()) patterns
|
|
106
116
|
this.expressionResolver.captureFunctionDeclaration(node);
|
|
107
117
|
break;
|
|
108
118
|
}
|
|
@@ -97,7 +97,7 @@ async function runExtractor(config, options = {}) {
|
|
|
97
97
|
// always show the funnel regardless of cooldown.
|
|
98
98
|
if (anyFileUpdated && !options.isDryRun && !options.quiet)
|
|
99
99
|
await printLocizeFunnel(options.logger, anyNewFile);
|
|
100
|
-
return { anyFileUpdated, hasErrors: fileErrors.length > 0 };
|
|
100
|
+
return { anyFileUpdated, hasErrors: fileErrors.length > 0, results };
|
|
101
101
|
}
|
|
102
102
|
catch (error) {
|
|
103
103
|
spinner.fail(styleText('red', 'Extraction failed.'));
|
|
@@ -16,6 +16,11 @@ class ExpressionResolver {
|
|
|
16
16
|
// Shared (cross-file) table for type aliases — populated alongside typeAliasTable.
|
|
17
17
|
// Persists across resetFileSymbols() so exported type aliases are visible to importers.
|
|
18
18
|
sharedTypeAliasTable = new Map();
|
|
19
|
+
// Shared (cross-file) table for function return-value sets. Populated from
|
|
20
|
+
// both explicit return-type annotations and body-inferred return values so
|
|
21
|
+
// that `t(fn())` / `const x = fn(); t(\`...${x}...\`)` work across files.
|
|
22
|
+
// Persists across resetFileSymbols() just like the other shared tables.
|
|
23
|
+
sharedFunctionReturnTable = new Map();
|
|
19
24
|
// Temporary per-scope variable overrides, used to inject .map() / .forEach()
|
|
20
25
|
// callback parameters while the callback body is being walked.
|
|
21
26
|
temporaryVariables = new Map();
|
|
@@ -166,15 +171,23 @@ class ExpressionResolver {
|
|
|
166
171
|
return;
|
|
167
172
|
}
|
|
168
173
|
// pattern 3 (arrow function variant):
|
|
169
|
-
// `const fn = (): 'a' | 'b' => ...` — capture the explicit return type annotation
|
|
174
|
+
// `const fn = (): 'a' | 'b' => ...` — capture the explicit return type annotation,
|
|
175
|
+
// OR fall back to walking the body's return expressions / expression body
|
|
176
|
+
// when no annotation is present (mirrors TS's own return-type inference).
|
|
170
177
|
if (unwrappedInit.type === 'ArrowFunctionExpression' || unwrappedInit.type === 'FunctionExpression') {
|
|
178
|
+
let returnVals = [];
|
|
171
179
|
const rawReturnType = unwrappedInit.returnType ?? unwrappedInit.typeAnnotation;
|
|
172
180
|
if (rawReturnType) {
|
|
181
|
+
// Explicit annotation — trust it even when it resolves to [].
|
|
173
182
|
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
returnVals = this.resolvePossibleStringValuesFromType(tsType);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
returnVals = this.inferReturnValuesFromFunctionBody(unwrappedInit);
|
|
187
|
+
}
|
|
188
|
+
if (returnVals.length > 0) {
|
|
189
|
+
this.variableTable.set(name, returnVals);
|
|
190
|
+
this.sharedFunctionReturnTable.set(name, returnVals);
|
|
178
191
|
}
|
|
179
192
|
}
|
|
180
193
|
}
|
|
@@ -229,19 +242,85 @@ class ExpressionResolver {
|
|
|
229
242
|
// or directly in `.returnType` (FunctionExpression / ArrowFunctionExpression).
|
|
230
243
|
const fn = node.function ?? node;
|
|
231
244
|
const rawReturnType = fn.returnType ?? fn.typeAnnotation;
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
245
|
+
let vals = [];
|
|
246
|
+
if (rawReturnType) {
|
|
247
|
+
// Unwrap TsTypeAnnotation wrapper if present. Explicit annotations are
|
|
248
|
+
// authoritative: if the author declared the return type we trust it,
|
|
249
|
+
// even when it resolves to [] (e.g. plain `string`). Falling back to
|
|
250
|
+
// body inference in that case would invent keys the author deliberately
|
|
251
|
+
// opted out of.
|
|
252
|
+
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
253
|
+
vals = this.resolvePossibleStringValuesFromType(tsType);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// No annotation — infer from body. Mirrors TS's own return-type
|
|
257
|
+
// inference for functions like:
|
|
258
|
+
// function getCurrentAppType() {
|
|
259
|
+
// if (...) return OrganizationType.ROUTING;
|
|
260
|
+
// if (...) return OrganizationType.CONTRACTOR;
|
|
261
|
+
// }
|
|
262
|
+
vals = this.inferReturnValuesFromFunctionBody(fn);
|
|
263
|
+
}
|
|
237
264
|
if (vals.length > 0) {
|
|
238
265
|
this.variableTable.set(name, vals);
|
|
266
|
+
this.sharedFunctionReturnTable.set(name, vals);
|
|
239
267
|
}
|
|
240
268
|
}
|
|
241
269
|
catch {
|
|
242
270
|
// noop
|
|
243
271
|
}
|
|
244
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Walk a function body's ReturnStatements and union the statically-resolvable
|
|
275
|
+
* string values of their argument expressions. Does NOT descend into nested
|
|
276
|
+
* function declarations (their returns belong to the inner function, not us).
|
|
277
|
+
*
|
|
278
|
+
* This is how we mirror TypeScript's implicit return-type inference for the
|
|
279
|
+
* purpose of extracting translation keys — we don't need exhaustiveness, just
|
|
280
|
+
* the set of string values any return statement could produce.
|
|
281
|
+
*/
|
|
282
|
+
inferReturnValuesFromFunctionBody(fn) {
|
|
283
|
+
const body = fn?.body;
|
|
284
|
+
if (!body)
|
|
285
|
+
return [];
|
|
286
|
+
const collected = [];
|
|
287
|
+
const visit = (n) => {
|
|
288
|
+
if (!n || typeof n !== 'object')
|
|
289
|
+
return;
|
|
290
|
+
// Don't descend into nested function bodies — their returns aren't ours.
|
|
291
|
+
if (n !== body && (n.type === 'FunctionDeclaration' ||
|
|
292
|
+
n.type === 'FunctionExpression' ||
|
|
293
|
+
n.type === 'ArrowFunctionExpression'))
|
|
294
|
+
return;
|
|
295
|
+
if (n.type === 'ReturnStatement' && n.argument) {
|
|
296
|
+
const vals = this.resolvePossibleStringValuesFromExpression(n.argument);
|
|
297
|
+
if (vals.length > 0)
|
|
298
|
+
collected.push(...vals);
|
|
299
|
+
}
|
|
300
|
+
for (const key of Object.keys(n)) {
|
|
301
|
+
const child = n[key];
|
|
302
|
+
if (Array.isArray(child)) {
|
|
303
|
+
for (const item of child) {
|
|
304
|
+
if (item && typeof item === 'object')
|
|
305
|
+
visit(item);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else if (child && typeof child === 'object' && typeof child.type === 'string') {
|
|
309
|
+
visit(child);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
// Arrow functions with an expression body (no BlockStatement) — `() => expr` —
|
|
314
|
+
// have their return expression directly as `body`.
|
|
315
|
+
if (body.type !== 'BlockStatement') {
|
|
316
|
+
const vals = this.resolvePossibleStringValuesFromExpression(body);
|
|
317
|
+
if (vals.length > 0)
|
|
318
|
+
return Array.from(new Set(vals));
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
visit(body);
|
|
322
|
+
return Array.from(new Set(collected));
|
|
323
|
+
}
|
|
245
324
|
/**
|
|
246
325
|
* Extract a raw TsType node from an identifier's type annotation.
|
|
247
326
|
* SWC may wrap it in a `TsTypeAnnotation` node — this unwraps it.
|
|
@@ -501,7 +580,10 @@ class ExpressionResolver {
|
|
|
501
580
|
catch { }
|
|
502
581
|
}
|
|
503
582
|
// pattern 3:
|
|
504
|
-
// `t(fn())` — resolve to the function's known return-
|
|
583
|
+
// `t(fn())` — resolve to the function's known return-value set (either
|
|
584
|
+
// from an explicit annotation or inferred from the function body). Check
|
|
585
|
+
// the per-file variable table first (same-file capture) and fall back to
|
|
586
|
+
// the shared cross-file table populated during pre-scan.
|
|
505
587
|
if (expression.type === 'CallExpression') {
|
|
506
588
|
try {
|
|
507
589
|
const callee = expression.callee;
|
|
@@ -509,6 +591,9 @@ class ExpressionResolver {
|
|
|
509
591
|
const v = this.variableTable.get(callee.value);
|
|
510
592
|
if (Array.isArray(v) && v.length > 0)
|
|
511
593
|
return v;
|
|
594
|
+
const sv = this.sharedFunctionReturnTable.get(callee.value);
|
|
595
|
+
if (sv && sv.length > 0)
|
|
596
|
+
return sv;
|
|
512
597
|
}
|
|
513
598
|
}
|
|
514
599
|
catch { }
|
package/package.json
CHANGED
package/types/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAoBnC,QAAA,MAAM,OAAO,SAAgB,CAAA;AAiZ7B,OAAO,EAAE,OAAO,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-visitors.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/ast-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAQ,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC7G,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AAItE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,KAAK,CAAiB;IAE9B,IAAW,UAAU,gBAEpB;IAED,SAAgB,YAAY,EAAE,YAAY,CAAA;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAuB;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAAa;IAEhC;;;;;;OAMG;gBAED,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,eAAe,EACvB,kBAAkB,CAAC,EAAE,kBAAkB;IAiCzC;;;;;;;;;;;;;OAaG;IACI,mBAAmB,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK/C;;;OAGG;IACH,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"ast-visitors.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/ast-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAQ,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC7G,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AAItE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,KAAK,CAAiB;IAE9B,IAAW,UAAU,gBAEpB;IAED,SAAgB,YAAY,EAAE,YAAY,CAAA;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAuB;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAAa;IAEhC;;;;;;OAMG;gBAED,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,eAAe,EACvB,kBAAkB,CAAC,EAAE,kBAAkB;IAiCzC;;;;;;;;;;;;;OAaG;IACI,mBAAmB,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK/C;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IA8CzB;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAUjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IAoXZ;;;;;;;;OAQG;IACH,OAAO,CAAC,gCAAgC;IAqDxC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAqB5B;;;;;;;;OAQG;IACI,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI5D;;OAEG;IACI,cAAc,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxD;;;;;;OAMG;IACI,cAAc,IAAK,MAAM;IAIhC;;OAEG;IACI,cAAc,IAAK,MAAM;CAGjC"}
|
|
@@ -37,6 +37,7 @@ export declare function runExtractor(config: I18nextToolkitConfig, options?: {
|
|
|
37
37
|
}): Promise<{
|
|
38
38
|
anyFileUpdated: boolean;
|
|
39
39
|
hasErrors: boolean;
|
|
40
|
+
results: TranslationResult[];
|
|
40
41
|
}>;
|
|
41
42
|
/**
|
|
42
43
|
* Processes an individual source file for translation key extraction.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAO5G,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAK/C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CACX,GACL,OAAO,CAAC;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAO5G,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAK/C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CACX,GACL,OAAO,CAAC;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAAE,CAAC,CA8ExF;AAwBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,GAAE,MAA4B,EACpC,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CAoJf;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,GAAE,MAA4B,EACpC,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CA6Df;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,OAAO,CAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,uBAA+B,EAAE,GAAE;IAAE,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAO1K"}
|
|
@@ -7,6 +7,7 @@ export declare class ExpressionResolver {
|
|
|
7
7
|
private typeAliasTable;
|
|
8
8
|
private sharedVariableTable;
|
|
9
9
|
private sharedTypeAliasTable;
|
|
10
|
+
private sharedFunctionReturnTable;
|
|
10
11
|
private temporaryVariables;
|
|
11
12
|
constructor(hooks: ASTVisitorHooks);
|
|
12
13
|
/**
|
|
@@ -44,6 +45,16 @@ export declare class ExpressionResolver {
|
|
|
44
45
|
* SWC node shapes: `FunctionDeclaration` / `FnDecl`
|
|
45
46
|
*/
|
|
46
47
|
captureFunctionDeclaration(node: any): void;
|
|
48
|
+
/**
|
|
49
|
+
* Walk a function body's ReturnStatements and union the statically-resolvable
|
|
50
|
+
* string values of their argument expressions. Does NOT descend into nested
|
|
51
|
+
* function declarations (their returns belong to the inner function, not us).
|
|
52
|
+
*
|
|
53
|
+
* This is how we mirror TypeScript's implicit return-type inference for the
|
|
54
|
+
* purpose of extracting translation keys — we don't need exhaustiveness, just
|
|
55
|
+
* the set of string values any return statement could produce.
|
|
56
|
+
*/
|
|
57
|
+
private inferReturnValuesFromFunctionBody;
|
|
47
58
|
/**
|
|
48
59
|
* Extract a raw TsType node from an identifier's type annotation.
|
|
49
60
|
* SWC may wrap it in a `TsTypeAnnotation` node — this unwraps it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expression-resolver.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/expression-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAkD,MAAM,WAAW,CAAA;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAiB;IAK9B,OAAO,CAAC,aAAa,CAA4D;IAGjF,OAAO,CAAC,eAAe,CAAiD;IAIxE,OAAO,CAAC,cAAc,CAAmC;IAIzD,OAAO,CAAC,mBAAmB,CAAmC;IAI9D,OAAO,CAAC,oBAAoB,CAAmC;
|
|
1
|
+
{"version":3,"file":"expression-resolver.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/expression-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAkD,MAAM,WAAW,CAAA;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAiB;IAK9B,OAAO,CAAC,aAAa,CAA4D;IAGjF,OAAO,CAAC,eAAe,CAAiD;IAIxE,OAAO,CAAC,cAAc,CAAmC;IAIzD,OAAO,CAAC,mBAAmB,CAAmC;IAI9D,OAAO,CAAC,oBAAoB,CAAmC;IAM/D,OAAO,CAAC,yBAAyB,CAAmC;IAIpE,OAAO,CAAC,kBAAkB,CAAmC;gBAEhD,KAAK,EAAE,eAAe;IAInC;;OAEG;IACI,gBAAgB,IAAK,IAAI;IAMhC;;;;;;;;;OASG;IACH,yBAAyB,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IA2J3C;;;;;;;OAOG;IACH,2BAA2B,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAkB7C;;;;;;;;;OASG;IACH,0BAA0B,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAqC5C;;;;;;;;OAQG;IACH,OAAO,CAAC,iCAAiC;IA6CzC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;;OAIG;IACI,oBAAoB,CAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAIlE;;OAEG;IACI,uBAAuB,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAInD;;;;OAIG;IACI,yBAAyB,CAAE,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE;IAQxD;;;OAGG;IACI,iBAAiB,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IAQ7D;;;;OAIG;IACI,YAAY,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;IAQtE;;;;;OAKG;IACH,sBAAsB,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAwBxC;;;;;;;OAOG;IACH,kCAAkC,CAAE,UAAU,EAAE,UAAU,GAAG,MAAM,EAAE;IAKrE;;;;;;;OAOG;IACH,8BAA8B,CAAE,UAAU,EAAE,UAAU,GAAG,MAAM,EAAE;IAKjE;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,yCAAyC;IA2NjD,OAAO,CAAC,mCAAmC;IAiH3C;;;;;;OAMG;IACH,OAAO,CAAC,6CAA6C;IAyBrD;;;;;;OAMG;IACH,OAAO,CAAC,kDAAkD;CAwB3D"}
|