i18next-cli 1.48.1 → 1.49.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 +1 -1
- package/dist/cjs/extractor/core/ast-visitors.js +29 -1
- package/dist/cjs/extractor/parsers/call-expression-handler.js +5 -3
- package/dist/cjs/extractor/parsers/expression-resolver.js +156 -3
- package/dist/esm/cli.js +1 -1
- package/dist/esm/extractor/core/ast-visitors.js +29 -1
- package/dist/esm/extractor/parsers/call-expression-handler.js +5 -3
- package/dist/esm/extractor/parsers/expression-resolver.js +156 -3
- package/package.json +1 -1
- package/types/extractor/core/ast-visitors.d.ts.map +1 -1
- package/types/extractor/parsers/call-expression-handler.d.ts +2 -1
- package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
- package/types/extractor/parsers/expression-resolver.d.ts +26 -0
- package/types/extractor/parsers/expression-resolver.d.ts.map +1 -1
package/dist/cjs/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ const program = new commander.Command();
|
|
|
31
31
|
program
|
|
32
32
|
.name('i18next-cli')
|
|
33
33
|
.description('A unified, high-performance i18next CLI.')
|
|
34
|
-
.version('1.
|
|
34
|
+
.version('1.49.0'); // This string is replaced with the actual version at build time by rollup
|
|
35
35
|
// new: global config override option
|
|
36
36
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
37
37
|
program
|
|
@@ -61,7 +61,7 @@ class ASTVisitors {
|
|
|
61
61
|
this.scopeManager = new scopeManager.ScopeManager(config);
|
|
62
62
|
// use shared resolver when provided so captured enums/objects are visible across files
|
|
63
63
|
this.expressionResolver = expressionResolver$1 ?? new expressionResolver.ExpressionResolver(this.hooks);
|
|
64
|
-
this.callExpressionHandler = new callExpressionHandler.CallExpressionHandler(config, pluginContext, logger, this.expressionResolver, () => this.getCurrentFile(), () => this.getCurrentCode());
|
|
64
|
+
this.callExpressionHandler = new callExpressionHandler.CallExpressionHandler(config, pluginContext, logger, this.expressionResolver, () => this.getCurrentFile(), () => this.getCurrentCode(), (name) => this.scopeManager.resolveSimpleStringIdentifier(name));
|
|
65
65
|
this.jsxHandler = new jsxHandler.JSXHandler(config, pluginContext, this.expressionResolver, () => this.getCurrentFile(), () => this.getCurrentCode());
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
@@ -273,6 +273,17 @@ class ASTVisitors {
|
|
|
273
273
|
// capture enums into resolver symbol table
|
|
274
274
|
this.expressionResolver.captureEnumDeclaration(node);
|
|
275
275
|
break;
|
|
276
|
+
// pattern 2: capture type aliases so `declare const x: Alias` can be resolved
|
|
277
|
+
case 'TsTypeAliasDeclaration':
|
|
278
|
+
case 'TSTypeAliasDeclaration':
|
|
279
|
+
case 'TsTypeAliasDecl':
|
|
280
|
+
this.expressionResolver.captureTypeAliasDeclaration(node);
|
|
281
|
+
break;
|
|
282
|
+
// pattern 3: capture function return types so `t(fn())` can be resolved
|
|
283
|
+
case 'FunctionDeclaration':
|
|
284
|
+
case 'FnDecl':
|
|
285
|
+
this.expressionResolver.captureFunctionDeclaration(node);
|
|
286
|
+
break;
|
|
276
287
|
case 'CallExpression':
|
|
277
288
|
this.callExpressionHandler.handleCallExpression(node, this.scopeManager.getVarFromScope.bind(this.scopeManager));
|
|
278
289
|
break;
|
|
@@ -316,6 +327,23 @@ class ASTVisitors {
|
|
|
316
327
|
this.expressionResolver.captureEnumDeclaration(item);
|
|
317
328
|
// continue to allow further traversal
|
|
318
329
|
}
|
|
330
|
+
// pre-scan type alias declarations and function declarations
|
|
331
|
+
if (item.type === 'TsTypeAliasDeclaration' || item.type === 'TSTypeAliasDeclaration' || item.type === 'TsTypeAliasDecl') {
|
|
332
|
+
this.expressionResolver.captureTypeAliasDeclaration(item);
|
|
333
|
+
}
|
|
334
|
+
if (item.type === 'FunctionDeclaration' || item.type === 'FnDecl') {
|
|
335
|
+
this.expressionResolver.captureFunctionDeclaration(item);
|
|
336
|
+
}
|
|
337
|
+
// Also handle ExportDeclaration wrapping either of the above
|
|
338
|
+
if ((item.type === 'ExportDeclaration' || item.type === 'ExportNamedDeclaration') && item.declaration) {
|
|
339
|
+
const decl = item.declaration;
|
|
340
|
+
if (decl.type === 'TsTypeAliasDeclaration' || decl.type === 'TSTypeAliasDeclaration' || decl.type === 'TsTypeAliasDecl') {
|
|
341
|
+
this.expressionResolver.captureTypeAliasDeclaration(decl);
|
|
342
|
+
}
|
|
343
|
+
if (decl.type === 'FunctionDeclaration' || decl.type === 'FnDecl') {
|
|
344
|
+
this.expressionResolver.captureFunctionDeclaration(decl);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
319
347
|
// Common case: VariableDeclaration which contains .declarations (VariableDeclarator[])
|
|
320
348
|
if (item.type === 'VariableDeclaration' && Array.isArray(item.declarations)) {
|
|
321
349
|
for (const decl of item.declarations) {
|
|
@@ -12,13 +12,15 @@ class CallExpressionHandler {
|
|
|
12
12
|
objectKeys = new Set();
|
|
13
13
|
getCurrentFile;
|
|
14
14
|
getCurrentCode;
|
|
15
|
-
|
|
15
|
+
resolveIdentifier;
|
|
16
|
+
constructor(config, pluginContext, logger, expressionResolver, getCurrentFile, getCurrentCode, resolveIdentifier = () => undefined) {
|
|
16
17
|
this.config = config;
|
|
17
18
|
this.pluginContext = pluginContext;
|
|
18
19
|
this.logger = logger;
|
|
19
20
|
this.expressionResolver = expressionResolver;
|
|
20
21
|
this.getCurrentFile = getCurrentFile;
|
|
21
22
|
this.getCurrentCode = getCurrentCode;
|
|
23
|
+
this.resolveIdentifier = resolveIdentifier;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Computes line and column from a node's normalised span.
|
|
@@ -153,8 +155,8 @@ class CallExpressionHandler {
|
|
|
153
155
|
// Determine namespace (explicit ns > ns:key > scope ns > default)
|
|
154
156
|
// See https://www.i18next.com/overview/api#getfixedt
|
|
155
157
|
if (options) {
|
|
156
|
-
const nsVal = astUtils.getObjectPropValue(options, 'ns');
|
|
157
|
-
if (typeof nsVal === 'string')
|
|
158
|
+
const nsVal = astUtils.getObjectPropValue(options, 'ns', this.resolveIdentifier);
|
|
159
|
+
if (typeof nsVal === 'string' && nsVal !== '')
|
|
158
160
|
ns = nsVal;
|
|
159
161
|
}
|
|
160
162
|
const nsSeparator = this.config.extract.nsSeparator ?? ':';
|
|
@@ -9,6 +9,9 @@ class ExpressionResolver {
|
|
|
9
9
|
variableTable = new Map();
|
|
10
10
|
// Shared (cross-file) table for enums / exported object maps that should persist
|
|
11
11
|
sharedEnumTable = new Map();
|
|
12
|
+
// Per-file table for type aliases: Maps typeName -> string[]
|
|
13
|
+
// e.g. `type ChangeType = 'all' | 'next' | 'this'` -> { ChangeType: ['all', 'next', 'this'] }
|
|
14
|
+
typeAliasTable = new Map();
|
|
12
15
|
constructor(hooks) {
|
|
13
16
|
this.hooks = hooks;
|
|
14
17
|
}
|
|
@@ -17,6 +20,7 @@ class ExpressionResolver {
|
|
|
17
20
|
*/
|
|
18
21
|
resetFileSymbols() {
|
|
19
22
|
this.variableTable.clear();
|
|
23
|
+
this.typeAliasTable.clear();
|
|
20
24
|
}
|
|
21
25
|
/**
|
|
22
26
|
* Capture a VariableDeclarator node to record simple statically analyzable
|
|
@@ -30,17 +34,39 @@ class ExpressionResolver {
|
|
|
30
34
|
*/
|
|
31
35
|
captureVariableDeclarator(node) {
|
|
32
36
|
try {
|
|
33
|
-
if (!node || !node.id
|
|
37
|
+
if (!node || !node.id)
|
|
34
38
|
return;
|
|
35
39
|
// only handle simple identifier bindings like `const x = ...`
|
|
36
40
|
if (node.id.type !== 'Identifier')
|
|
37
41
|
return;
|
|
38
42
|
const name = node.id.value;
|
|
43
|
+
// pattern 1:
|
|
44
|
+
// Handle `declare const x: 'a' | 'b'` and `declare const x: SomeUnion`
|
|
45
|
+
// where there is no initializer but a TypeScript type annotation.
|
|
46
|
+
if (!node.init) {
|
|
47
|
+
const typeAnnotation = this.extractTypeAnnotation(node.id);
|
|
48
|
+
if (typeAnnotation) {
|
|
49
|
+
const vals = this.resolvePossibleStringValuesFromType(typeAnnotation);
|
|
50
|
+
if (vals.length > 0) {
|
|
51
|
+
this.variableTable.set(name, vals);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
39
56
|
const init = node.init;
|
|
57
|
+
// Unwrap TS type assertion wrappers before inspecting the shape of the initializer.
|
|
58
|
+
// `{ ... } as const` → TsConstAssertion; `x as Type` → TsAsExpression; etc.
|
|
59
|
+
// We need the raw expression to detect ObjectExpression and ArrowFunctionExpression.
|
|
60
|
+
let unwrappedInit = init;
|
|
61
|
+
while (unwrappedInit?.type === 'TsConstAssertion' ||
|
|
62
|
+
unwrappedInit?.type === 'TsAsExpression' ||
|
|
63
|
+
unwrappedInit?.type === 'TsSatisfiesExpression') {
|
|
64
|
+
unwrappedInit = unwrappedInit.expression;
|
|
65
|
+
}
|
|
40
66
|
// ObjectExpression -> map of string props
|
|
41
|
-
if (
|
|
67
|
+
if (unwrappedInit.type === 'ObjectExpression' && Array.isArray(unwrappedInit.properties)) {
|
|
42
68
|
const map = {};
|
|
43
|
-
for (const p of
|
|
69
|
+
for (const p of unwrappedInit.properties) {
|
|
44
70
|
if (!p || p.type !== 'KeyValueProperty')
|
|
45
71
|
continue;
|
|
46
72
|
const keyNode = p.key;
|
|
@@ -64,12 +90,96 @@ class ExpressionResolver {
|
|
|
64
90
|
const vals = this.resolvePossibleStringValuesFromExpression(init);
|
|
65
91
|
if (vals.length > 0) {
|
|
66
92
|
this.variableTable.set(name, vals);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// pattern 3 (arrow function variant):
|
|
96
|
+
// `const fn = (): 'a' | 'b' => ...` — capture the explicit return type annotation.
|
|
97
|
+
if (unwrappedInit.type === 'ArrowFunctionExpression' || unwrappedInit.type === 'FunctionExpression') {
|
|
98
|
+
const rawReturnType = unwrappedInit.returnType ?? unwrappedInit.typeAnnotation;
|
|
99
|
+
if (rawReturnType) {
|
|
100
|
+
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
101
|
+
const returnVals = this.resolvePossibleStringValuesFromType(tsType);
|
|
102
|
+
if (returnVals.length > 0) {
|
|
103
|
+
this.variableTable.set(name, returnVals);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
67
106
|
}
|
|
68
107
|
}
|
|
69
108
|
catch {
|
|
70
109
|
// be silent - conservative only
|
|
71
110
|
}
|
|
72
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Capture a TypeScript type alias so that `declare const x: AliasName` can
|
|
114
|
+
* be resolved to its string union members later.
|
|
115
|
+
*
|
|
116
|
+
* Handles: `type Foo = 'a' | 'b' | 'c'`
|
|
117
|
+
*
|
|
118
|
+
* SWC node shapes: `TsTypeAliasDeclaration` / `TsTypeAliasDecl`
|
|
119
|
+
*/
|
|
120
|
+
captureTypeAliasDeclaration(node) {
|
|
121
|
+
try {
|
|
122
|
+
const name = node?.id?.type === 'Identifier' ? node.id.value : undefined;
|
|
123
|
+
if (!name)
|
|
124
|
+
return;
|
|
125
|
+
// SWC puts the actual type in `.typeAnnotation`
|
|
126
|
+
const tsType = node.typeAnnotation ?? node.typeAnn;
|
|
127
|
+
if (!tsType)
|
|
128
|
+
return;
|
|
129
|
+
const vals = this.resolvePossibleStringValuesFromType(tsType);
|
|
130
|
+
if (vals.length > 0) {
|
|
131
|
+
this.typeAliasTable.set(name, vals);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// noop
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Capture the return-type annotation of a function declaration so that
|
|
140
|
+
* `t(fn())` calls can be expanded to all union members.
|
|
141
|
+
*
|
|
142
|
+
* Handles both `function f(): 'a' | 'b' { ... }` and
|
|
143
|
+
* `const f = (): 'a' | 'b' => ...` (the arrow-function form is captured
|
|
144
|
+
* via captureVariableDeclarator when the init is an ArrowFunctionExpression).
|
|
145
|
+
*
|
|
146
|
+
* SWC node shapes: `FunctionDeclaration` / `FnDecl`
|
|
147
|
+
*/
|
|
148
|
+
captureFunctionDeclaration(node) {
|
|
149
|
+
try {
|
|
150
|
+
const name = node?.identifier?.value ?? node?.id?.value;
|
|
151
|
+
if (!name)
|
|
152
|
+
return;
|
|
153
|
+
// SWC places the return type annotation in `.function.returnType` (FunctionDeclaration)
|
|
154
|
+
// or directly in `.returnType` (FunctionExpression / ArrowFunctionExpression).
|
|
155
|
+
const fn = node.function ?? node;
|
|
156
|
+
const rawReturnType = fn.returnType ?? fn.typeAnnotation;
|
|
157
|
+
if (!rawReturnType)
|
|
158
|
+
return;
|
|
159
|
+
// Unwrap TsTypeAnnotation wrapper if present
|
|
160
|
+
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
161
|
+
const vals = this.resolvePossibleStringValuesFromType(tsType);
|
|
162
|
+
if (vals.length > 0) {
|
|
163
|
+
this.variableTable.set(name, vals);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// noop
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Extract a raw TsType node from an identifier's type annotation.
|
|
172
|
+
* SWC may wrap it in a `TsTypeAnnotation` node — this unwraps it.
|
|
173
|
+
*/
|
|
174
|
+
extractTypeAnnotation(idNode) {
|
|
175
|
+
const raw = idNode?.typeAnnotation;
|
|
176
|
+
if (!raw)
|
|
177
|
+
return undefined;
|
|
178
|
+
// TsTypeAnnotation wrapper -> .typeAnnotation holds the actual TsType
|
|
179
|
+
if (raw.type === 'TsTypeAnnotation')
|
|
180
|
+
return raw.typeAnnotation;
|
|
181
|
+
return raw;
|
|
182
|
+
}
|
|
73
183
|
/**
|
|
74
184
|
* Capture a TypeScript enum declaration so members can be resolved later.
|
|
75
185
|
* Accepts SWC node shapes like `TsEnumDeclaration` / `TSEnumDeclaration`.
|
|
@@ -220,11 +330,36 @@ class ExpressionResolver {
|
|
|
220
330
|
if (propName && base[propName] !== undefined) {
|
|
221
331
|
return [base[propName]];
|
|
222
332
|
}
|
|
333
|
+
// pattern 4:
|
|
334
|
+
// `map[identifierVar]` where identifierVar resolves to a known set of keys.
|
|
335
|
+
// Try to enumerate which map values are reachable.
|
|
336
|
+
if (prop.type === 'Computed' && prop.expression) {
|
|
337
|
+
const keyVals = this.resolvePossibleStringValuesFromExpression(prop.expression, returnEmptyStrings);
|
|
338
|
+
if (keyVals.length > 0) {
|
|
339
|
+
// Return only the map values for the known keys (subset access)
|
|
340
|
+
return keyVals.map(k => base[k]).filter((v) => v !== undefined);
|
|
341
|
+
}
|
|
342
|
+
// Cannot narrow the key at all — return all map values as a conservative fallback
|
|
343
|
+
return Object.values(base);
|
|
344
|
+
}
|
|
223
345
|
}
|
|
224
346
|
}
|
|
225
347
|
}
|
|
226
348
|
catch { }
|
|
227
349
|
}
|
|
350
|
+
// pattern 3:
|
|
351
|
+
// `t(fn())` — resolve to the function's known return-type union when captured.
|
|
352
|
+
if (expression.type === 'CallExpression') {
|
|
353
|
+
try {
|
|
354
|
+
const callee = expression.callee;
|
|
355
|
+
if (callee?.type === 'Identifier') {
|
|
356
|
+
const v = this.variableTable.get(callee.value);
|
|
357
|
+
if (Array.isArray(v) && v.length > 0)
|
|
358
|
+
return v;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch { }
|
|
362
|
+
}
|
|
228
363
|
// Binary concatenation support (e.g., a + '_' + b)
|
|
229
364
|
// SWC binary expr can be represented as `BinExpr` with left/right; be permissive:
|
|
230
365
|
if (expression.left && expression.right) {
|
|
@@ -279,6 +414,11 @@ class ExpressionResolver {
|
|
|
279
414
|
const annotation = expression.typeAnnotation;
|
|
280
415
|
return this.resolvePossibleStringValuesFromType(annotation, returnEmptyStrings);
|
|
281
416
|
}
|
|
417
|
+
// `expr as const` — delegate to the underlying expression (the type annotation is
|
|
418
|
+
// just `const`, which carries no union information, so we want the value side).
|
|
419
|
+
if (expression.type === 'TsConstAssertion') {
|
|
420
|
+
return this.resolvePossibleStringValuesFromExpression(expression.expression, returnEmptyStrings);
|
|
421
|
+
}
|
|
282
422
|
// Identifier resolution via captured per-file variable table only
|
|
283
423
|
if (expression.type === 'Identifier') {
|
|
284
424
|
const v = this.variableTable.get(expression.value);
|
|
@@ -308,6 +448,19 @@ class ExpressionResolver {
|
|
|
308
448
|
return [`${type.literal.value}`]; // Handle literals like 5 or true
|
|
309
449
|
}
|
|
310
450
|
}
|
|
451
|
+
// pattern 2:
|
|
452
|
+
// Resolve a named type alias reference: `declare const x: ChangeType`
|
|
453
|
+
// where `type ChangeType = 'all' | 'next' | 'this'` was captured earlier.
|
|
454
|
+
if (type.type === 'TsTypeReference') {
|
|
455
|
+
const typeName = type.typeName?.type === 'Identifier'
|
|
456
|
+
? type.typeName.value
|
|
457
|
+
: undefined;
|
|
458
|
+
if (typeName) {
|
|
459
|
+
const aliasVals = this.typeAliasTable.get(typeName);
|
|
460
|
+
if (aliasVals && aliasVals.length > 0)
|
|
461
|
+
return aliasVals;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
311
464
|
// We can't statically determine the value of other expressions (e.g., variables, function calls)
|
|
312
465
|
return [];
|
|
313
466
|
}
|
package/dist/esm/cli.js
CHANGED
|
@@ -29,7 +29,7 @@ const program = new Command();
|
|
|
29
29
|
program
|
|
30
30
|
.name('i18next-cli')
|
|
31
31
|
.description('A unified, high-performance i18next CLI.')
|
|
32
|
-
.version('1.
|
|
32
|
+
.version('1.49.0'); // This string is replaced with the actual version at build time by rollup
|
|
33
33
|
// new: global config override option
|
|
34
34
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
35
35
|
program
|
|
@@ -59,7 +59,7 @@ class ASTVisitors {
|
|
|
59
59
|
this.scopeManager = new ScopeManager(config);
|
|
60
60
|
// use shared resolver when provided so captured enums/objects are visible across files
|
|
61
61
|
this.expressionResolver = expressionResolver ?? new ExpressionResolver(this.hooks);
|
|
62
|
-
this.callExpressionHandler = new CallExpressionHandler(config, pluginContext, logger, this.expressionResolver, () => this.getCurrentFile(), () => this.getCurrentCode());
|
|
62
|
+
this.callExpressionHandler = new CallExpressionHandler(config, pluginContext, logger, this.expressionResolver, () => this.getCurrentFile(), () => this.getCurrentCode(), (name) => this.scopeManager.resolveSimpleStringIdentifier(name));
|
|
63
63
|
this.jsxHandler = new JSXHandler(config, pluginContext, this.expressionResolver, () => this.getCurrentFile(), () => this.getCurrentCode());
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
@@ -271,6 +271,17 @@ class ASTVisitors {
|
|
|
271
271
|
// capture enums into resolver symbol table
|
|
272
272
|
this.expressionResolver.captureEnumDeclaration(node);
|
|
273
273
|
break;
|
|
274
|
+
// pattern 2: capture type aliases so `declare const x: Alias` can be resolved
|
|
275
|
+
case 'TsTypeAliasDeclaration':
|
|
276
|
+
case 'TSTypeAliasDeclaration':
|
|
277
|
+
case 'TsTypeAliasDecl':
|
|
278
|
+
this.expressionResolver.captureTypeAliasDeclaration(node);
|
|
279
|
+
break;
|
|
280
|
+
// pattern 3: capture function return types so `t(fn())` can be resolved
|
|
281
|
+
case 'FunctionDeclaration':
|
|
282
|
+
case 'FnDecl':
|
|
283
|
+
this.expressionResolver.captureFunctionDeclaration(node);
|
|
284
|
+
break;
|
|
274
285
|
case 'CallExpression':
|
|
275
286
|
this.callExpressionHandler.handleCallExpression(node, this.scopeManager.getVarFromScope.bind(this.scopeManager));
|
|
276
287
|
break;
|
|
@@ -314,6 +325,23 @@ class ASTVisitors {
|
|
|
314
325
|
this.expressionResolver.captureEnumDeclaration(item);
|
|
315
326
|
// continue to allow further traversal
|
|
316
327
|
}
|
|
328
|
+
// pre-scan type alias declarations and function declarations
|
|
329
|
+
if (item.type === 'TsTypeAliasDeclaration' || item.type === 'TSTypeAliasDeclaration' || item.type === 'TsTypeAliasDecl') {
|
|
330
|
+
this.expressionResolver.captureTypeAliasDeclaration(item);
|
|
331
|
+
}
|
|
332
|
+
if (item.type === 'FunctionDeclaration' || item.type === 'FnDecl') {
|
|
333
|
+
this.expressionResolver.captureFunctionDeclaration(item);
|
|
334
|
+
}
|
|
335
|
+
// Also handle ExportDeclaration wrapping either of the above
|
|
336
|
+
if ((item.type === 'ExportDeclaration' || item.type === 'ExportNamedDeclaration') && item.declaration) {
|
|
337
|
+
const decl = item.declaration;
|
|
338
|
+
if (decl.type === 'TsTypeAliasDeclaration' || decl.type === 'TSTypeAliasDeclaration' || decl.type === 'TsTypeAliasDecl') {
|
|
339
|
+
this.expressionResolver.captureTypeAliasDeclaration(decl);
|
|
340
|
+
}
|
|
341
|
+
if (decl.type === 'FunctionDeclaration' || decl.type === 'FnDecl') {
|
|
342
|
+
this.expressionResolver.captureFunctionDeclaration(decl);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
317
345
|
// Common case: VariableDeclaration which contains .declarations (VariableDeclarator[])
|
|
318
346
|
if (item.type === 'VariableDeclaration' && Array.isArray(item.declarations)) {
|
|
319
347
|
for (const decl of item.declarations) {
|
|
@@ -10,13 +10,15 @@ class CallExpressionHandler {
|
|
|
10
10
|
objectKeys = new Set();
|
|
11
11
|
getCurrentFile;
|
|
12
12
|
getCurrentCode;
|
|
13
|
-
|
|
13
|
+
resolveIdentifier;
|
|
14
|
+
constructor(config, pluginContext, logger, expressionResolver, getCurrentFile, getCurrentCode, resolveIdentifier = () => undefined) {
|
|
14
15
|
this.config = config;
|
|
15
16
|
this.pluginContext = pluginContext;
|
|
16
17
|
this.logger = logger;
|
|
17
18
|
this.expressionResolver = expressionResolver;
|
|
18
19
|
this.getCurrentFile = getCurrentFile;
|
|
19
20
|
this.getCurrentCode = getCurrentCode;
|
|
21
|
+
this.resolveIdentifier = resolveIdentifier;
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
24
|
* Computes line and column from a node's normalised span.
|
|
@@ -151,8 +153,8 @@ class CallExpressionHandler {
|
|
|
151
153
|
// Determine namespace (explicit ns > ns:key > scope ns > default)
|
|
152
154
|
// See https://www.i18next.com/overview/api#getfixedt
|
|
153
155
|
if (options) {
|
|
154
|
-
const nsVal = getObjectPropValue(options, 'ns');
|
|
155
|
-
if (typeof nsVal === 'string')
|
|
156
|
+
const nsVal = getObjectPropValue(options, 'ns', this.resolveIdentifier);
|
|
157
|
+
if (typeof nsVal === 'string' && nsVal !== '')
|
|
156
158
|
ns = nsVal;
|
|
157
159
|
}
|
|
158
160
|
const nsSeparator = this.config.extract.nsSeparator ?? ':';
|
|
@@ -7,6 +7,9 @@ class ExpressionResolver {
|
|
|
7
7
|
variableTable = new Map();
|
|
8
8
|
// Shared (cross-file) table for enums / exported object maps that should persist
|
|
9
9
|
sharedEnumTable = new Map();
|
|
10
|
+
// Per-file table for type aliases: Maps typeName -> string[]
|
|
11
|
+
// e.g. `type ChangeType = 'all' | 'next' | 'this'` -> { ChangeType: ['all', 'next', 'this'] }
|
|
12
|
+
typeAliasTable = new Map();
|
|
10
13
|
constructor(hooks) {
|
|
11
14
|
this.hooks = hooks;
|
|
12
15
|
}
|
|
@@ -15,6 +18,7 @@ class ExpressionResolver {
|
|
|
15
18
|
*/
|
|
16
19
|
resetFileSymbols() {
|
|
17
20
|
this.variableTable.clear();
|
|
21
|
+
this.typeAliasTable.clear();
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* Capture a VariableDeclarator node to record simple statically analyzable
|
|
@@ -28,17 +32,39 @@ class ExpressionResolver {
|
|
|
28
32
|
*/
|
|
29
33
|
captureVariableDeclarator(node) {
|
|
30
34
|
try {
|
|
31
|
-
if (!node || !node.id
|
|
35
|
+
if (!node || !node.id)
|
|
32
36
|
return;
|
|
33
37
|
// only handle simple identifier bindings like `const x = ...`
|
|
34
38
|
if (node.id.type !== 'Identifier')
|
|
35
39
|
return;
|
|
36
40
|
const name = node.id.value;
|
|
41
|
+
// pattern 1:
|
|
42
|
+
// Handle `declare const x: 'a' | 'b'` and `declare const x: SomeUnion`
|
|
43
|
+
// where there is no initializer but a TypeScript type annotation.
|
|
44
|
+
if (!node.init) {
|
|
45
|
+
const typeAnnotation = this.extractTypeAnnotation(node.id);
|
|
46
|
+
if (typeAnnotation) {
|
|
47
|
+
const vals = this.resolvePossibleStringValuesFromType(typeAnnotation);
|
|
48
|
+
if (vals.length > 0) {
|
|
49
|
+
this.variableTable.set(name, vals);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
37
54
|
const init = node.init;
|
|
55
|
+
// Unwrap TS type assertion wrappers before inspecting the shape of the initializer.
|
|
56
|
+
// `{ ... } as const` → TsConstAssertion; `x as Type` → TsAsExpression; etc.
|
|
57
|
+
// We need the raw expression to detect ObjectExpression and ArrowFunctionExpression.
|
|
58
|
+
let unwrappedInit = init;
|
|
59
|
+
while (unwrappedInit?.type === 'TsConstAssertion' ||
|
|
60
|
+
unwrappedInit?.type === 'TsAsExpression' ||
|
|
61
|
+
unwrappedInit?.type === 'TsSatisfiesExpression') {
|
|
62
|
+
unwrappedInit = unwrappedInit.expression;
|
|
63
|
+
}
|
|
38
64
|
// ObjectExpression -> map of string props
|
|
39
|
-
if (
|
|
65
|
+
if (unwrappedInit.type === 'ObjectExpression' && Array.isArray(unwrappedInit.properties)) {
|
|
40
66
|
const map = {};
|
|
41
|
-
for (const p of
|
|
67
|
+
for (const p of unwrappedInit.properties) {
|
|
42
68
|
if (!p || p.type !== 'KeyValueProperty')
|
|
43
69
|
continue;
|
|
44
70
|
const keyNode = p.key;
|
|
@@ -62,12 +88,96 @@ class ExpressionResolver {
|
|
|
62
88
|
const vals = this.resolvePossibleStringValuesFromExpression(init);
|
|
63
89
|
if (vals.length > 0) {
|
|
64
90
|
this.variableTable.set(name, vals);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// pattern 3 (arrow function variant):
|
|
94
|
+
// `const fn = (): 'a' | 'b' => ...` — capture the explicit return type annotation.
|
|
95
|
+
if (unwrappedInit.type === 'ArrowFunctionExpression' || unwrappedInit.type === 'FunctionExpression') {
|
|
96
|
+
const rawReturnType = unwrappedInit.returnType ?? unwrappedInit.typeAnnotation;
|
|
97
|
+
if (rawReturnType) {
|
|
98
|
+
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
99
|
+
const returnVals = this.resolvePossibleStringValuesFromType(tsType);
|
|
100
|
+
if (returnVals.length > 0) {
|
|
101
|
+
this.variableTable.set(name, returnVals);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
65
104
|
}
|
|
66
105
|
}
|
|
67
106
|
catch {
|
|
68
107
|
// be silent - conservative only
|
|
69
108
|
}
|
|
70
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Capture a TypeScript type alias so that `declare const x: AliasName` can
|
|
112
|
+
* be resolved to its string union members later.
|
|
113
|
+
*
|
|
114
|
+
* Handles: `type Foo = 'a' | 'b' | 'c'`
|
|
115
|
+
*
|
|
116
|
+
* SWC node shapes: `TsTypeAliasDeclaration` / `TsTypeAliasDecl`
|
|
117
|
+
*/
|
|
118
|
+
captureTypeAliasDeclaration(node) {
|
|
119
|
+
try {
|
|
120
|
+
const name = node?.id?.type === 'Identifier' ? node.id.value : undefined;
|
|
121
|
+
if (!name)
|
|
122
|
+
return;
|
|
123
|
+
// SWC puts the actual type in `.typeAnnotation`
|
|
124
|
+
const tsType = node.typeAnnotation ?? node.typeAnn;
|
|
125
|
+
if (!tsType)
|
|
126
|
+
return;
|
|
127
|
+
const vals = this.resolvePossibleStringValuesFromType(tsType);
|
|
128
|
+
if (vals.length > 0) {
|
|
129
|
+
this.typeAliasTable.set(name, vals);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// noop
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Capture the return-type annotation of a function declaration so that
|
|
138
|
+
* `t(fn())` calls can be expanded to all union members.
|
|
139
|
+
*
|
|
140
|
+
* Handles both `function f(): 'a' | 'b' { ... }` and
|
|
141
|
+
* `const f = (): 'a' | 'b' => ...` (the arrow-function form is captured
|
|
142
|
+
* via captureVariableDeclarator when the init is an ArrowFunctionExpression).
|
|
143
|
+
*
|
|
144
|
+
* SWC node shapes: `FunctionDeclaration` / `FnDecl`
|
|
145
|
+
*/
|
|
146
|
+
captureFunctionDeclaration(node) {
|
|
147
|
+
try {
|
|
148
|
+
const name = node?.identifier?.value ?? node?.id?.value;
|
|
149
|
+
if (!name)
|
|
150
|
+
return;
|
|
151
|
+
// SWC places the return type annotation in `.function.returnType` (FunctionDeclaration)
|
|
152
|
+
// or directly in `.returnType` (FunctionExpression / ArrowFunctionExpression).
|
|
153
|
+
const fn = node.function ?? node;
|
|
154
|
+
const rawReturnType = fn.returnType ?? fn.typeAnnotation;
|
|
155
|
+
if (!rawReturnType)
|
|
156
|
+
return;
|
|
157
|
+
// Unwrap TsTypeAnnotation wrapper if present
|
|
158
|
+
const tsType = rawReturnType.typeAnnotation ?? rawReturnType;
|
|
159
|
+
const vals = this.resolvePossibleStringValuesFromType(tsType);
|
|
160
|
+
if (vals.length > 0) {
|
|
161
|
+
this.variableTable.set(name, vals);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// noop
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Extract a raw TsType node from an identifier's type annotation.
|
|
170
|
+
* SWC may wrap it in a `TsTypeAnnotation` node — this unwraps it.
|
|
171
|
+
*/
|
|
172
|
+
extractTypeAnnotation(idNode) {
|
|
173
|
+
const raw = idNode?.typeAnnotation;
|
|
174
|
+
if (!raw)
|
|
175
|
+
return undefined;
|
|
176
|
+
// TsTypeAnnotation wrapper -> .typeAnnotation holds the actual TsType
|
|
177
|
+
if (raw.type === 'TsTypeAnnotation')
|
|
178
|
+
return raw.typeAnnotation;
|
|
179
|
+
return raw;
|
|
180
|
+
}
|
|
71
181
|
/**
|
|
72
182
|
* Capture a TypeScript enum declaration so members can be resolved later.
|
|
73
183
|
* Accepts SWC node shapes like `TsEnumDeclaration` / `TSEnumDeclaration`.
|
|
@@ -218,11 +328,36 @@ class ExpressionResolver {
|
|
|
218
328
|
if (propName && base[propName] !== undefined) {
|
|
219
329
|
return [base[propName]];
|
|
220
330
|
}
|
|
331
|
+
// pattern 4:
|
|
332
|
+
// `map[identifierVar]` where identifierVar resolves to a known set of keys.
|
|
333
|
+
// Try to enumerate which map values are reachable.
|
|
334
|
+
if (prop.type === 'Computed' && prop.expression) {
|
|
335
|
+
const keyVals = this.resolvePossibleStringValuesFromExpression(prop.expression, returnEmptyStrings);
|
|
336
|
+
if (keyVals.length > 0) {
|
|
337
|
+
// Return only the map values for the known keys (subset access)
|
|
338
|
+
return keyVals.map(k => base[k]).filter((v) => v !== undefined);
|
|
339
|
+
}
|
|
340
|
+
// Cannot narrow the key at all — return all map values as a conservative fallback
|
|
341
|
+
return Object.values(base);
|
|
342
|
+
}
|
|
221
343
|
}
|
|
222
344
|
}
|
|
223
345
|
}
|
|
224
346
|
catch { }
|
|
225
347
|
}
|
|
348
|
+
// pattern 3:
|
|
349
|
+
// `t(fn())` — resolve to the function's known return-type union when captured.
|
|
350
|
+
if (expression.type === 'CallExpression') {
|
|
351
|
+
try {
|
|
352
|
+
const callee = expression.callee;
|
|
353
|
+
if (callee?.type === 'Identifier') {
|
|
354
|
+
const v = this.variableTable.get(callee.value);
|
|
355
|
+
if (Array.isArray(v) && v.length > 0)
|
|
356
|
+
return v;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
catch { }
|
|
360
|
+
}
|
|
226
361
|
// Binary concatenation support (e.g., a + '_' + b)
|
|
227
362
|
// SWC binary expr can be represented as `BinExpr` with left/right; be permissive:
|
|
228
363
|
if (expression.left && expression.right) {
|
|
@@ -277,6 +412,11 @@ class ExpressionResolver {
|
|
|
277
412
|
const annotation = expression.typeAnnotation;
|
|
278
413
|
return this.resolvePossibleStringValuesFromType(annotation, returnEmptyStrings);
|
|
279
414
|
}
|
|
415
|
+
// `expr as const` — delegate to the underlying expression (the type annotation is
|
|
416
|
+
// just `const`, which carries no union information, so we want the value side).
|
|
417
|
+
if (expression.type === 'TsConstAssertion') {
|
|
418
|
+
return this.resolvePossibleStringValuesFromExpression(expression.expression, returnEmptyStrings);
|
|
419
|
+
}
|
|
280
420
|
// Identifier resolution via captured per-file variable table only
|
|
281
421
|
if (expression.type === 'Identifier') {
|
|
282
422
|
const v = this.variableTable.get(expression.value);
|
|
@@ -306,6 +446,19 @@ class ExpressionResolver {
|
|
|
306
446
|
return [`${type.literal.value}`]; // Handle literals like 5 or true
|
|
307
447
|
}
|
|
308
448
|
}
|
|
449
|
+
// pattern 2:
|
|
450
|
+
// Resolve a named type alias reference: `declare const x: ChangeType`
|
|
451
|
+
// where `type ChangeType = 'all' | 'next' | 'this'` was captured earlier.
|
|
452
|
+
if (type.type === 'TsTypeReference') {
|
|
453
|
+
const typeName = type.typeName?.type === 'Identifier'
|
|
454
|
+
? type.typeName.value
|
|
455
|
+
: undefined;
|
|
456
|
+
if (typeName) {
|
|
457
|
+
const aliasVals = this.typeAliasTable.get(typeName);
|
|
458
|
+
if (aliasVals && aliasVals.length > 0)
|
|
459
|
+
return aliasVals;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
309
462
|
// We can't statically determine the value of other expressions (e.g., variables, function calls)
|
|
310
463
|
return [];
|
|
311
464
|
}
|
package/package.json
CHANGED
|
@@ -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,aAAa,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAInE;;;;;;;;;;;;;;;;;;;;;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;
|
|
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,aAAa,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAInE;;;;;;;;;;;;;;;;;;;;;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;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAUjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IAgRZ;;;;;;;;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"}
|
|
@@ -9,7 +9,8 @@ export declare class CallExpressionHandler {
|
|
|
9
9
|
objectKeys: Set<string>;
|
|
10
10
|
private getCurrentFile;
|
|
11
11
|
private getCurrentCode;
|
|
12
|
-
|
|
12
|
+
private resolveIdentifier;
|
|
13
|
+
constructor(config: Omit<I18nextToolkitConfig, 'plugins'>, pluginContext: PluginContext, logger: Logger, expressionResolver: ExpressionResolver, getCurrentFile: () => string, getCurrentCode: () => string, resolveIdentifier?: (name: string) => string | undefined);
|
|
13
14
|
/**
|
|
14
15
|
* Computes line and column from a node's normalised span.
|
|
15
16
|
* For call / new expressions the location points to the first argument
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,aAAa,CAAA;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAM1D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;
|
|
1
|
+
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,aAAa,CAAA;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAM1D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,iBAAiB,CAAsC;gBAG7D,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM,EAC5B,iBAAiB,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAA2B;IAW3E;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IAgYxG;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,oBAAoB;IA6E5B,OAAO,CAAC,wBAAwB;IAyEhC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IAyMxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
|
|
@@ -4,6 +4,7 @@ export declare class ExpressionResolver {
|
|
|
4
4
|
private hooks;
|
|
5
5
|
private variableTable;
|
|
6
6
|
private sharedEnumTable;
|
|
7
|
+
private typeAliasTable;
|
|
7
8
|
constructor(hooks: ASTVisitorHooks);
|
|
8
9
|
/**
|
|
9
10
|
* Clear per-file captured variables. Enums / shared maps are kept.
|
|
@@ -20,6 +21,31 @@ export declare class ExpressionResolver {
|
|
|
20
21
|
* @param node - VariableDeclarator-like node (has .id and .init)
|
|
21
22
|
*/
|
|
22
23
|
captureVariableDeclarator(node: any): void;
|
|
24
|
+
/**
|
|
25
|
+
* Capture a TypeScript type alias so that `declare const x: AliasName` can
|
|
26
|
+
* be resolved to its string union members later.
|
|
27
|
+
*
|
|
28
|
+
* Handles: `type Foo = 'a' | 'b' | 'c'`
|
|
29
|
+
*
|
|
30
|
+
* SWC node shapes: `TsTypeAliasDeclaration` / `TsTypeAliasDecl`
|
|
31
|
+
*/
|
|
32
|
+
captureTypeAliasDeclaration(node: any): void;
|
|
33
|
+
/**
|
|
34
|
+
* Capture the return-type annotation of a function declaration so that
|
|
35
|
+
* `t(fn())` calls can be expanded to all union members.
|
|
36
|
+
*
|
|
37
|
+
* Handles both `function f(): 'a' | 'b' { ... }` and
|
|
38
|
+
* `const f = (): 'a' | 'b' => ...` (the arrow-function form is captured
|
|
39
|
+
* via captureVariableDeclarator when the init is an ArrowFunctionExpression).
|
|
40
|
+
*
|
|
41
|
+
* SWC node shapes: `FunctionDeclaration` / `FnDecl`
|
|
42
|
+
*/
|
|
43
|
+
captureFunctionDeclaration(node: any): void;
|
|
44
|
+
/**
|
|
45
|
+
* Extract a raw TsType node from an identifier's type annotation.
|
|
46
|
+
* SWC may wrap it in a `TsTypeAnnotation` node — this unwraps it.
|
|
47
|
+
*/
|
|
48
|
+
private extractTypeAnnotation;
|
|
23
49
|
/**
|
|
24
50
|
* Capture a TypeScript enum declaration so members can be resolved later.
|
|
25
51
|
* Accepts SWC node shapes like `TsEnumDeclaration` / `TSEnumDeclaration`.
|
|
@@ -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,aAAa,CAAA;AAElD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAiB;IAK9B,OAAO,CAAC,aAAa,CAA4D;IAGjF,OAAO,CAAC,eAAe,CAAiD;
|
|
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,aAAa,CAAA;AAElD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAiB;IAK9B,OAAO,CAAC,aAAa,CAA4D;IAGjF,OAAO,CAAC,eAAe,CAAiD;IAIxE,OAAO,CAAC,cAAc,CAAmC;gBAE5C,KAAK,EAAE,eAAe;IAInC;;OAEG;IACI,gBAAgB,IAAK,IAAI;IAKhC;;;;;;;;;OASG;IACH,yBAAyB,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAiF3C;;;;;;;OAOG;IACH,2BAA2B,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAgB7C;;;;;;;;;OASG;IACH,0BAA0B,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAoB5C;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;;;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;IAwLjD,OAAO,CAAC,mCAAmC;IAsC3C;;;;;;OAMG;IACH,OAAO,CAAC,6CAA6C;IAyBrD;;;;;;OAMG;IACH,OAAO,CAAC,kDAAkD;CAwB3D"}
|