i18next-cli 1.48.0 → 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 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.48.0'); // This string is replaced with the actual version at build time by rollup
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
- constructor(config, pluginContext, logger, expressionResolver, getCurrentFile, getCurrentCode) {
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 || !node.init)
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 (init.type === 'ObjectExpression' && Array.isArray(init.properties)) {
67
+ if (unwrappedInit.type === 'ObjectExpression' && Array.isArray(unwrappedInit.properties)) {
42
68
  const map = {};
43
- for (const p of init.properties) {
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
  }
@@ -10,6 +10,10 @@ class ScopeManager {
10
10
  simpleConstants = new Map();
11
11
  // Track simple local constant objects with string literal property values
12
12
  simpleConstantObjects = new Map();
13
+ // Shared (cross-file) tables so that exported constants from one file can be
14
+ // resolved when imported in another. These are NOT cleared by reset().
15
+ sharedConstants = new Map();
16
+ sharedConstantObjects = new Map();
13
17
  constructor(config) {
14
18
  this.config = config;
15
19
  }
@@ -135,7 +139,7 @@ class ScopeManager {
135
139
  * Resolve simple identifier declared in-file to its string literal value, if known.
136
140
  */
137
141
  resolveSimpleStringIdentifier(name) {
138
- return this.simpleConstants.get(name);
142
+ return this.simpleConstants.get(name) ?? this.sharedConstants.get(name);
139
143
  }
140
144
  /**
141
145
  * Resolve a MemberExpression node (e.g., `ns.custom`) to its string value
@@ -145,7 +149,7 @@ class ScopeManager {
145
149
  if (node.object.type !== 'Identifier') {
146
150
  return undefined;
147
151
  }
148
- const map = this.simpleConstantObjects.get(node.object.value);
152
+ const map = this.simpleConstantObjects.get(node.object.value) ?? this.sharedConstantObjects.get(node.object.value);
149
153
  if (!map) {
150
154
  return undefined;
151
155
  }
@@ -180,6 +184,7 @@ class ScopeManager {
180
184
  const unwrapped = ScopeManager.unwrapTsExpression(init);
181
185
  if (unwrapped?.type === 'StringLiteral') {
182
186
  this.simpleConstants.set(node.id.value, unwrapped.value);
187
+ this.sharedConstants.set(node.id.value, unwrapped.value);
183
188
  }
184
189
  else if (unwrapped?.type === 'ObjectExpression' && Array.isArray(unwrapped.properties)) {
185
190
  const map = {};
@@ -202,12 +207,14 @@ class ScopeManager {
202
207
  }
203
208
  if (Object.keys(map).length > 0) {
204
209
  this.simpleConstantObjects.set(node.id.value, map);
210
+ this.sharedConstantObjects.set(node.id.value, map);
205
211
  }
206
212
  }
207
213
  else {
208
214
  const fromType = ScopeManager.extractStringFromTypeAnnotation(node);
209
215
  if (fromType !== undefined) {
210
216
  this.simpleConstants.set(node.id.value, fromType);
217
+ this.sharedConstants.set(node.id.value, fromType);
211
218
  }
212
219
  }
213
220
  // continue processing; still may be a useTranslation/getFixedT call below
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.48.0'); // This string is replaced with the actual version at build time by rollup
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
- constructor(config, pluginContext, logger, expressionResolver, getCurrentFile, getCurrentCode) {
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 || !node.init)
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 (init.type === 'ObjectExpression' && Array.isArray(init.properties)) {
65
+ if (unwrappedInit.type === 'ObjectExpression' && Array.isArray(unwrappedInit.properties)) {
40
66
  const map = {};
41
- for (const p of init.properties) {
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
  }
@@ -8,6 +8,10 @@ class ScopeManager {
8
8
  simpleConstants = new Map();
9
9
  // Track simple local constant objects with string literal property values
10
10
  simpleConstantObjects = new Map();
11
+ // Shared (cross-file) tables so that exported constants from one file can be
12
+ // resolved when imported in another. These are NOT cleared by reset().
13
+ sharedConstants = new Map();
14
+ sharedConstantObjects = new Map();
11
15
  constructor(config) {
12
16
  this.config = config;
13
17
  }
@@ -133,7 +137,7 @@ class ScopeManager {
133
137
  * Resolve simple identifier declared in-file to its string literal value, if known.
134
138
  */
135
139
  resolveSimpleStringIdentifier(name) {
136
- return this.simpleConstants.get(name);
140
+ return this.simpleConstants.get(name) ?? this.sharedConstants.get(name);
137
141
  }
138
142
  /**
139
143
  * Resolve a MemberExpression node (e.g., `ns.custom`) to its string value
@@ -143,7 +147,7 @@ class ScopeManager {
143
147
  if (node.object.type !== 'Identifier') {
144
148
  return undefined;
145
149
  }
146
- const map = this.simpleConstantObjects.get(node.object.value);
150
+ const map = this.simpleConstantObjects.get(node.object.value) ?? this.sharedConstantObjects.get(node.object.value);
147
151
  if (!map) {
148
152
  return undefined;
149
153
  }
@@ -178,6 +182,7 @@ class ScopeManager {
178
182
  const unwrapped = ScopeManager.unwrapTsExpression(init);
179
183
  if (unwrapped?.type === 'StringLiteral') {
180
184
  this.simpleConstants.set(node.id.value, unwrapped.value);
185
+ this.sharedConstants.set(node.id.value, unwrapped.value);
181
186
  }
182
187
  else if (unwrapped?.type === 'ObjectExpression' && Array.isArray(unwrapped.properties)) {
183
188
  const map = {};
@@ -200,12 +205,14 @@ class ScopeManager {
200
205
  }
201
206
  if (Object.keys(map).length > 0) {
202
207
  this.simpleConstantObjects.set(node.id.value, map);
208
+ this.sharedConstantObjects.set(node.id.value, map);
203
209
  }
204
210
  }
205
211
  else {
206
212
  const fromType = ScopeManager.extractStringFromTypeAnnotation(node);
207
213
  if (fromType !== undefined) {
208
214
  this.simpleConstants.set(node.id.value, fromType);
215
+ this.sharedConstants.set(node.id.value, fromType);
209
216
  }
210
217
  }
211
218
  // continue processing; still may be a useTranslation/getFixedT call below
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next-cli",
3
- "version": "1.48.0",
3
+ "version": "1.49.0",
4
4
  "description": "A unified, high-performance i18next CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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;IAgCzC;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAUjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IAoPZ;;;;;;;;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"}
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
- constructor(config: Omit<I18nextToolkitConfig, 'plugins'>, pluginContext: PluginContext, logger: Logger, expressionResolver: ExpressionResolver, getCurrentFile: () => string, getCurrentCode: () => string);
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;gBAGlC,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;IAU9B;;;;;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"}
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;gBAE3D,KAAK,EAAE,eAAe;IAInC;;OAEG;IACI,gBAAgB,IAAK,IAAI;IAIhC;;;;;;;;;OASG;IACH,yBAAyB,CAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAwC3C;;;;;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;IAyJjD,OAAO,CAAC,mCAAmC;IAwB3C;;;;;;OAMG;IACH,OAAO,CAAC,6CAA6C;IAyBrD;;;;;;OAMG;IACH,OAAO,CAAC,kDAAkD;CAwB3D"}
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"}
@@ -6,6 +6,8 @@ export declare class ScopeManager {
6
6
  private scope;
7
7
  private simpleConstants;
8
8
  private simpleConstantObjects;
9
+ private sharedConstants;
10
+ private sharedConstantObjects;
9
11
  constructor(config: Omit<I18nextToolkitConfig, 'plugins'>);
10
12
  /**
11
13
  * Recursively unwraps TypeScript type assertion wrappers to reach the
@@ -1 +1 @@
1
- {"version":3,"file":"scope-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/scope-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAMnB,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,SAAS,EAA4B,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAG5F,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,KAAK,CAAqE;IAGlF,OAAO,CAAC,eAAe,CAAiC;IAGxD,OAAO,CAAC,qBAAqB,CAAiD;gBAEjE,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC;IAI1D;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAcjC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,+BAA+B;IAgB9C;;;;;;OAMG;IACI,KAAK,IAAK,IAAI;IAOrB;;;OAGG;IACH,UAAU,IAAK,IAAI;IAInB;;;OAGG;IACH,SAAS,IAAK,IAAI;IAIlB;;;;;;OAMG;IACH,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAUnD;;;;;;OAMG;IACH,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAkBrD,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACI,6BAA6B,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIvE;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAqBrC;;;;;;;;;;OAUG;IACH,wBAAwB,CAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAuFzD;;;;;;;;OAQG;IACH,OAAO,CAAC,+BAA+B;IA0GvC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,8BAA8B;IAmFtC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;;;OASG;IACH,OAAO,CAAC,qCAAqC;CAuB9C"}
1
+ {"version":3,"file":"scope-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/scope-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAMnB,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,SAAS,EAA4B,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAG5F,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,KAAK,CAAqE;IAGlF,OAAO,CAAC,eAAe,CAAiC;IAGxD,OAAO,CAAC,qBAAqB,CAAiD;IAI9E,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,qBAAqB,CAAiD;gBAEjE,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC;IAI1D;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAcjC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,+BAA+B;IAgB9C;;;;;;OAMG;IACI,KAAK,IAAK,IAAI;IAOrB;;;OAGG;IACH,UAAU,IAAK,IAAI;IAInB;;;OAGG;IACH,SAAS,IAAK,IAAI;IAIlB;;;;;;OAMG;IACH,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAUnD;;;;;;OAMG;IACH,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAkBrD,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACI,6BAA6B,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIvE;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAqBrC;;;;;;;;;;OAUG;IACH,wBAAwB,CAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IA0FzD;;;;;;;;OAQG;IACH,OAAO,CAAC,+BAA+B;IA0GvC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,8BAA8B;IAmFtC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;;;OASG;IACH,OAAO,CAAC,qCAAqC;CAuB9C"}