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 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.1'); // 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
  }
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.1'); // 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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next-cli",
3
- "version": "1.48.1",
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"}