i18next-cli 1.10.1 → 1.10.3

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -0
  3. package/dist/cjs/cli.js +1 -1
  4. package/dist/cjs/extractor/core/ast-visitors.js +1 -0
  5. package/dist/cjs/extractor/core/key-finder.js +1 -1
  6. package/dist/cjs/extractor/core/translation-manager.js +1 -1
  7. package/dist/cjs/extractor/parsers/call-expression-handler.js +1 -0
  8. package/dist/cjs/extractor/parsers/expression-resolver.js +1 -0
  9. package/dist/cjs/extractor/parsers/jsx-handler.js +1 -0
  10. package/dist/cjs/extractor/parsers/jsx-parser.js +1 -1
  11. package/dist/cjs/extractor/parsers/scope-manager.js +1 -0
  12. package/dist/esm/cli.js +1 -1
  13. package/dist/esm/extractor/core/ast-visitors.js +1 -0
  14. package/dist/esm/extractor/core/key-finder.js +1 -1
  15. package/dist/esm/extractor/core/translation-manager.js +1 -1
  16. package/dist/esm/extractor/parsers/call-expression-handler.js +1 -0
  17. package/dist/esm/extractor/parsers/expression-resolver.js +1 -0
  18. package/dist/esm/extractor/parsers/jsx-handler.js +1 -0
  19. package/dist/esm/extractor/parsers/jsx-parser.js +1 -1
  20. package/dist/esm/extractor/parsers/scope-manager.js +1 -0
  21. package/package.json +1 -1
  22. package/src/cli.ts +1 -1
  23. package/src/extractor/core/ast-visitors.ts +170 -0
  24. package/src/extractor/core/extractor.ts +1 -1
  25. package/src/extractor/core/key-finder.ts +2 -2
  26. package/src/extractor/core/translation-manager.ts +88 -8
  27. package/src/extractor/index.ts +1 -1
  28. package/src/extractor/parsers/call-expression-handler.ts +506 -0
  29. package/src/extractor/parsers/expression-resolver.ts +178 -0
  30. package/src/extractor/parsers/jsx-handler.ts +358 -0
  31. package/src/extractor/parsers/jsx-parser.ts +5 -1
  32. package/src/extractor/parsers/scope-manager.ts +327 -0
  33. package/src/extractor.ts +1 -1
  34. package/src/types.ts +82 -0
  35. package/types/extractor/core/ast-visitors.d.ts +75 -0
  36. package/types/extractor/core/ast-visitors.d.ts.map +1 -0
  37. package/types/extractor/core/extractor.d.ts +1 -1
  38. package/types/extractor/core/extractor.d.ts.map +1 -1
  39. package/types/extractor/core/key-finder.d.ts.map +1 -1
  40. package/types/extractor/core/translation-manager.d.ts.map +1 -1
  41. package/types/extractor/index.d.ts +1 -1
  42. package/types/extractor/index.d.ts.map +1 -1
  43. package/types/extractor/parsers/call-expression-handler.d.ts +74 -0
  44. package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -0
  45. package/types/extractor/parsers/expression-resolver.d.ts +62 -0
  46. package/types/extractor/parsers/expression-resolver.d.ts.map +1 -0
  47. package/types/extractor/parsers/jsx-handler.d.ts +44 -0
  48. package/types/extractor/parsers/jsx-handler.d.ts.map +1 -0
  49. package/types/extractor/parsers/scope-manager.d.ts +99 -0
  50. package/types/extractor/parsers/scope-manager.d.ts.map +1 -0
  51. package/types/extractor.d.ts +1 -1
  52. package/types/extractor.d.ts.map +1 -1
  53. package/types/types.d.ts +77 -0
  54. package/types/types.d.ts.map +1 -1
  55. package/dist/cjs/extractor/parsers/ast-visitors.js +0 -1
  56. package/dist/esm/extractor/parsers/ast-visitors.js +0 -1
  57. package/src/extractor/parsers/ast-visitors.ts +0 -1510
  58. package/types/extractor/parsers/ast-visitors.d.ts +0 -352
  59. package/types/extractor/parsers/ast-visitors.d.ts.map +0 -1
@@ -0,0 +1,327 @@
1
+ import type { VariableDeclarator, CallExpression } from '@swc/core'
2
+ import type { ScopeInfo, UseTranslationHookConfig, I18nextToolkitConfig } from '../../types'
3
+ import { getObjectPropValue } from './ast-utils'
4
+
5
+ export class ScopeManager {
6
+ private scopeStack: Array<Map<string, ScopeInfo>> = []
7
+ private config: Omit<I18nextToolkitConfig, 'plugins'>
8
+ private scope: Map<string, { defaultNs?: string; keyPrefix?: string }> = new Map()
9
+
10
+ constructor (config: Omit<I18nextToolkitConfig, 'plugins'>) {
11
+ this.config = config
12
+ }
13
+
14
+ /**
15
+ * Enters a new variable scope by pushing a new scope map onto the stack.
16
+ * Used when entering functions to isolate variable declarations.
17
+ */
18
+ enterScope (): void {
19
+ this.scopeStack.push(new Map())
20
+ }
21
+
22
+ /**
23
+ * Exits the current variable scope by popping the top scope map.
24
+ * Used when leaving functions to clean up variable tracking.
25
+ */
26
+ exitScope (): void {
27
+ this.scopeStack.pop()
28
+ }
29
+
30
+ /**
31
+ * Stores variable information in the current scope.
32
+ * Used to track translation functions and their configuration.
33
+ *
34
+ * @param name - Variable name to store
35
+ * @param info - Scope information about the variable
36
+ */
37
+ setVarInScope (name: string, info: ScopeInfo): void {
38
+ if (this.scopeStack.length > 0) {
39
+ this.scopeStack[this.scopeStack.length - 1].set(name, info)
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Retrieves variable information from the scope chain.
45
+ * Searches from innermost to outermost scope.
46
+ *
47
+ * @param name - Variable name to look up
48
+ * @returns Scope information if found, undefined otherwise
49
+ */
50
+ getVarFromScope (name: string): ScopeInfo | undefined {
51
+ // First check the proper scope stack (this is the primary source of truth)
52
+ for (let i = this.scopeStack.length - 1; i >= 0; i--) {
53
+ if (this.scopeStack[i].has(name)) {
54
+ const scopeInfo = this.scopeStack[i].get(name)
55
+ return scopeInfo
56
+ }
57
+ }
58
+
59
+ // Then check the legacy scope tracking for useTranslation calls (for comment parsing)
60
+ const legacyScope = this.scope.get(name)
61
+ if (legacyScope) {
62
+ return legacyScope
63
+ }
64
+
65
+ return undefined
66
+ }
67
+
68
+ /**
69
+ * Handles variable declarations that might define translation functions.
70
+ *
71
+ * Processes two patterns:
72
+ * 1. `const { t } = useTranslation(...)` - React i18next pattern
73
+ * 2. `const t = i18next.getFixedT(...)` - Core i18next pattern
74
+ *
75
+ * Extracts namespace and key prefix information for later use.
76
+ *
77
+ * @param node - Variable declarator node to process
78
+ */
79
+ handleVariableDeclarator (node: VariableDeclarator): void {
80
+ const init = node.init
81
+ if (!init) return
82
+
83
+ // Determine the actual call expression, looking inside AwaitExpressions.
84
+ const callExpr =
85
+ init.type === 'AwaitExpression' && init.argument.type === 'CallExpression'
86
+ ? init.argument
87
+ : init.type === 'CallExpression'
88
+ ? init
89
+ : null
90
+
91
+ if (!callExpr) return
92
+
93
+ const callee = callExpr.callee
94
+
95
+ // Handle: const { t } = useTranslation(...)
96
+ if (callee.type === 'Identifier') {
97
+ const hookConfig = this.getUseTranslationConfig(callee.value)
98
+ if (hookConfig) {
99
+ this.handleUseTranslationDeclarator(node, callExpr, hookConfig)
100
+
101
+ // ALSO store in the legacy scope for comment parsing compatibility
102
+ this.handleUseTranslationForComments(node, callExpr, hookConfig)
103
+ return
104
+ }
105
+ }
106
+
107
+ // Handle: const t = i18next.getFixedT(...)
108
+ if (
109
+ callee.type === 'MemberExpression' &&
110
+ callee.property.type === 'Identifier' &&
111
+ callee.property.value === 'getFixedT'
112
+ ) {
113
+ this.handleGetFixedTDeclarator(node, callExpr)
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Handles useTranslation calls for comment scope resolution.
119
+ * This is a separate method to store scope info in the legacy scope map
120
+ * that the comment parser can access.
121
+ *
122
+ * @param node - Variable declarator with useTranslation call
123
+ * @param callExpr - The CallExpression node representing the useTranslation invocation
124
+ * @param hookConfig - Configuration describing argument positions for namespace and keyPrefix
125
+ */
126
+ private getUseTranslationConfig (name: string): UseTranslationHookConfig | undefined {
127
+ const useTranslationNames = this.config.extract.useTranslationNames || ['useTranslation']
128
+
129
+ for (const item of useTranslationNames) {
130
+ if (typeof item === 'string' && item === name) {
131
+ // Default behavior for simple string entries
132
+ return { name, nsArg: 0, keyPrefixArg: 1 }
133
+ }
134
+ if (typeof item === 'object' && item.name === name) {
135
+ // Custom configuration with specified or default argument positions
136
+ return {
137
+ name: item.name,
138
+ nsArg: item.nsArg ?? 0,
139
+ keyPrefixArg: item.keyPrefixArg ?? 1,
140
+ }
141
+ }
142
+ }
143
+ return undefined
144
+ }
145
+
146
+ /**
147
+ * Processes useTranslation hook declarations to extract scope information.
148
+ *
149
+ * Handles various destructuring patterns:
150
+ * - `const [t] = useTranslation('ns')` - Array destructuring
151
+ * - `const { t } = useTranslation('ns')` - Object destructuring
152
+ * - `const { t: myT } = useTranslation('ns')` - Aliased destructuring
153
+ *
154
+ * Extracts namespace from the first argument and keyPrefix from options.
155
+ *
156
+ * @param node - Variable declarator with useTranslation call
157
+ * @param callExpr - The CallExpression node representing the useTranslation invocation
158
+ * @param hookConfig - Configuration describing argument positions for namespace and keyPrefix
159
+ */
160
+ private handleUseTranslationForComments (node: VariableDeclarator, callExpr: CallExpression, hookConfig: UseTranslationHookConfig): void {
161
+ let variableName: string | undefined
162
+
163
+ // Handle simple assignment: let t = useTranslation()
164
+ if (node.id.type === 'Identifier') {
165
+ variableName = node.id.value
166
+ }
167
+
168
+ // Handle array destructuring: const [t, i18n] = useTranslation()
169
+ if (node.id.type === 'ArrayPattern') {
170
+ const firstElement = node.id.elements[0]
171
+ if (firstElement?.type === 'Identifier') {
172
+ variableName = firstElement.value
173
+ }
174
+ }
175
+
176
+ // Handle object destructuring: const { t } or { t: t1 } = useTranslation()
177
+ if (node.id.type === 'ObjectPattern') {
178
+ for (const prop of node.id.properties) {
179
+ if (prop.type === 'AssignmentPatternProperty' && prop.key.type === 'Identifier' && prop.key.value === 't') {
180
+ // This handles { t = defaultT }
181
+ variableName = 't'
182
+ break
183
+ }
184
+ if (prop.type === 'KeyValuePatternProperty' && prop.key.type === 'Identifier' && prop.key.value === 't' && prop.value.type === 'Identifier') {
185
+ // This handles { t: myT }
186
+ variableName = prop.value.value
187
+ break
188
+ }
189
+ }
190
+ }
191
+
192
+ // If we couldn't find a `t` function being declared, exit
193
+ if (!variableName) return
194
+
195
+ // Extract namespace from useTranslation arguments
196
+ const nsArg = callExpr.arguments?.[hookConfig.nsArg]?.expression
197
+ const optionsArg = callExpr.arguments?.[hookConfig.keyPrefixArg]?.expression
198
+
199
+ let defaultNs: string | undefined
200
+ let keyPrefix: string | undefined
201
+
202
+ // Parse namespace argument
203
+ if (nsArg?.type === 'StringLiteral') {
204
+ defaultNs = nsArg.value
205
+ } else if (nsArg?.type === 'ArrayExpression' && nsArg.elements[0]?.expression.type === 'StringLiteral') {
206
+ defaultNs = nsArg.elements[0].expression.value
207
+ }
208
+
209
+ // Parse keyPrefix from options object
210
+ if (optionsArg?.type === 'ObjectExpression') {
211
+ const keyPrefixProp = optionsArg.properties.find(
212
+ prop => prop.type === 'KeyValueProperty' &&
213
+ prop.key.type === 'Identifier' &&
214
+ prop.key.value === 'keyPrefix'
215
+ )
216
+ if (keyPrefixProp?.type === 'KeyValueProperty' && keyPrefixProp.value.type === 'StringLiteral') {
217
+ keyPrefix = keyPrefixProp.value.value
218
+ }
219
+ }
220
+
221
+ // Store in the legacy scope map for comment parsing
222
+ if (defaultNs || keyPrefix) {
223
+ this.scope.set(variableName, { defaultNs, keyPrefix })
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Processes useTranslation hook declarations to extract scope information.
229
+ *
230
+ * Handles various destructuring patterns:
231
+ * - `const [t] = useTranslation('ns')` - Array destructuring
232
+ * - `const { t } = useTranslation('ns')` - Object destructuring
233
+ * - `const { t: myT } = useTranslation('ns')` - Aliased destructuring
234
+ *
235
+ * Extracts namespace from the first argument and keyPrefix from options.
236
+ *
237
+ * @param node - Variable declarator with useTranslation call
238
+ * @param callExpr - The CallExpression node representing the useTranslation invocation
239
+ * @param hookConfig - Configuration describing argument positions for namespace and keyPrefix
240
+ */
241
+ private handleUseTranslationDeclarator (node: VariableDeclarator, callExpr: CallExpression, hookConfig: UseTranslationHookConfig): void {
242
+ let variableName: string | undefined
243
+
244
+ // Handle simple assignment: let t = useTranslation()
245
+ if (node.id.type === 'Identifier') {
246
+ variableName = node.id.value
247
+ }
248
+
249
+ // Handle array destructuring: const [t, i18n] = useTranslation()
250
+ if (node.id.type === 'ArrayPattern') {
251
+ const firstElement = node.id.elements[0]
252
+ if (firstElement?.type === 'Identifier') {
253
+ variableName = firstElement.value
254
+ }
255
+ }
256
+
257
+ // Handle object destructuring: const { t } or { t: t1 } = useTranslation()
258
+ if (node.id.type === 'ObjectPattern') {
259
+ for (const prop of node.id.properties) {
260
+ if (prop.type === 'AssignmentPatternProperty' && prop.key.type === 'Identifier' && prop.key.value === 't') {
261
+ // This handles { t = defaultT }
262
+ variableName = 't'
263
+ break
264
+ }
265
+ if (prop.type === 'KeyValuePatternProperty' && prop.key.type === 'Identifier' && prop.key.value === 't' && prop.value.type === 'Identifier') {
266
+ // This handles { t: myT }
267
+ variableName = prop.value.value
268
+ break
269
+ }
270
+ }
271
+ }
272
+
273
+ // If we couldn't find a `t` function being declared, exit
274
+ if (!variableName) return
275
+
276
+ // Use the configured argument indices from hookConfig
277
+ const nsArg = callExpr.arguments?.[hookConfig.nsArg]?.expression
278
+
279
+ let defaultNs: string | undefined
280
+ if (nsArg?.type === 'StringLiteral') {
281
+ defaultNs = nsArg.value
282
+ } else if (nsArg?.type === 'ArrayExpression' && nsArg.elements[0]?.expression.type === 'StringLiteral') {
283
+ defaultNs = nsArg.elements[0].expression.value
284
+ }
285
+
286
+ const optionsArg = callExpr.arguments?.[hookConfig.keyPrefixArg]?.expression
287
+ let keyPrefix: string | undefined
288
+ if (optionsArg?.type === 'ObjectExpression') {
289
+ const kp = getObjectPropValue(optionsArg, 'keyPrefix')
290
+ keyPrefix = typeof kp === 'string' ? kp : undefined
291
+ }
292
+
293
+ // Store the scope info for the declared variable
294
+ this.setVarInScope(variableName, { defaultNs, keyPrefix })
295
+ }
296
+
297
+ /**
298
+ * Processes getFixedT function declarations to extract scope information.
299
+ *
300
+ * Handles the pattern: `const t = i18next.getFixedT(lng, ns, keyPrefix)`
301
+ * - Ignores the first argument (language)
302
+ * - Extracts namespace from the second argument
303
+ * - Extracts key prefix from the third argument
304
+ *
305
+ * @param node - Variable declarator with getFixedT call
306
+ * @param callExpr - The CallExpression node representing the getFixedT invocation
307
+ */
308
+ private handleGetFixedTDeclarator (node: VariableDeclarator, callExpr: CallExpression): void {
309
+ // Ensure we are assigning to a simple variable, e.g., const t = ...
310
+ if (node.id.type !== 'Identifier' || !node.init || node.init.type !== 'CallExpression') return
311
+
312
+ const variableName = node.id.value
313
+ const args = callExpr.arguments
314
+
315
+ // getFixedT(lng, ns, keyPrefix)
316
+ // We ignore the first argument (lng) for key extraction.
317
+ const nsArg = args[1]?.expression
318
+ const keyPrefixArg = args[2]?.expression
319
+
320
+ const defaultNs = (nsArg?.type === 'StringLiteral') ? nsArg.value : undefined
321
+ const keyPrefix = (keyPrefixArg?.type === 'StringLiteral') ? keyPrefixArg.value : undefined
322
+
323
+ if (defaultNs || keyPrefix) {
324
+ this.setVarInScope(variableName, { defaultNs, keyPrefix })
325
+ }
326
+ }
327
+ }
package/src/extractor.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { runExtractor, extract } from './extractor/core/extractor'
3
3
  import { findKeys } from './extractor/core/key-finder'
4
4
  import { getTranslations } from './extractor/core/translation-manager'
5
- import { ASTVisitors } from './extractor/parsers/ast-visitors'
5
+ import { ASTVisitors } from './extractor/core/ast-visitors'
6
6
  import type { PluginContext } from './types'
7
7
 
8
8
  export {
package/src/types.ts CHANGED
@@ -421,3 +421,85 @@ export interface ScopeInfo {
421
421
  /** Key prefix to prepend to all translation keys in this scope */
422
422
  keyPrefix?: string;
423
423
  }
424
+
425
+ /**
426
+ * Configuration for useTranslation hook patterns.
427
+ * Defines how to extract namespace and key prefix information from hook calls.
428
+ *
429
+ * @example
430
+ * ```typescript
431
+ * // For: const { t } = useTranslation('common', { keyPrefix: 'user' })
432
+ * const config: UseTranslationHookConfig = {
433
+ * name: 'useTranslation',
434
+ * nsArg: 0, // namespace is first argument
435
+ * keyPrefixArg: 1 // keyPrefix is in second argument (options object)
436
+ * }
437
+ * ```
438
+ */
439
+ export interface UseTranslationHookConfig {
440
+ /** The name of the hook function (e.g., 'useTranslation', 'getT') */
441
+ name: string;
442
+ /** Zero-based index of the argument containing the namespace */
443
+ nsArg: number;
444
+ /** Zero-based index of the argument containing options with keyPrefix */
445
+ keyPrefixArg: number;
446
+ }
447
+
448
+ /**
449
+ * Optional hooks for customizing AST visitor behavior during extraction.
450
+ * Allows plugins and external code to extend the visitor's capabilities.
451
+ *
452
+ * @example
453
+ * ```typescript
454
+ * const hooks: ASTVisitorHooks = {
455
+ * onBeforeVisitNode: (node) => {
456
+ * console.log(`Visiting ${node.type}`)
457
+ * },
458
+ *
459
+ * resolvePossibleKeyStringValues: (expression) => {
460
+ * // Custom logic to extract keys from complex expressions
461
+ * if (isCustomKeyExpression(expression)) {
462
+ * return ['custom.key.1', 'custom.key.2']
463
+ * }
464
+ * return []
465
+ * }
466
+ * }
467
+ * ```
468
+ */
469
+ export interface ASTVisitorHooks {
470
+ /**
471
+ * Called before visiting each AST node during traversal.
472
+ * Useful for logging, debugging, or pre-processing nodes.
473
+ *
474
+ * @param node - The AST node about to be visited
475
+ */
476
+ onBeforeVisitNode?: (node: Node) => void
477
+
478
+ /**
479
+ * Called after visiting each AST node during traversal.
480
+ * Useful for cleanup, post-processing, or collecting statistics.
481
+ *
482
+ * @param node - The AST node that was just visited
483
+ */
484
+ onAfterVisitNode?: (node: Node) => void
485
+
486
+ /**
487
+ * Custom resolver for extracting context values from expressions.
488
+ * Supplements the built-in expression resolution with plugin-specific logic.
489
+ *
490
+ * @param expression - The expression to extract context from
491
+ * @param returnEmptyStrings - Whether to include empty strings in results
492
+ * @returns Array of possible context string values
493
+ */
494
+ resolvePossibleContextStringValues?: (expression: Expression, returnEmptyStrings?: boolean) => string[]
495
+
496
+ /**
497
+ * Custom resolver for extracting translation keys from expressions.
498
+ * Supplements the built-in expression resolution with plugin-specific logic.
499
+ *
500
+ * @param expression - The expression to extract keys from
501
+ * @param returnEmptyStrings - Whether to include empty strings in results
502
+ * @returns Array of possible translation key values
503
+ */
504
+ resolvePossibleKeyStringValues?: (expression: Expression, returnEmptyStrings?: boolean) => string[]
505
+ }
@@ -0,0 +1,75 @@
1
+ import type { Module } from '@swc/core';
2
+ import type { PluginContext, I18nextToolkitConfig, Logger, ASTVisitorHooks, ScopeInfo } from '../../types';
3
+ /**
4
+ * AST visitor class that traverses JavaScript/TypeScript syntax trees to extract translation keys.
5
+ *
6
+ * This class implements a manual recursive walker that:
7
+ * - Maintains scope information for tracking useTranslation and getFixedT calls
8
+ * - Extracts keys from t() function calls with various argument patterns
9
+ * - Handles JSX Trans components with complex children serialization
10
+ * - Supports both string literals and selector API for type-safe keys
11
+ * - Processes pluralization and context variants
12
+ * - Manages namespace resolution from multiple sources
13
+ *
14
+ * The visitor respects configuration options for separators, function names,
15
+ * component names, and other extraction settings.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const visitors = new ASTVisitors(config, pluginContext, logger)
20
+ * visitors.visit(parsedAST)
21
+ *
22
+ * // The pluginContext will now contain all extracted keys
23
+ * ```
24
+ */
25
+ export declare class ASTVisitors {
26
+ private readonly pluginContext;
27
+ private readonly config;
28
+ private readonly logger;
29
+ private hooks;
30
+ get objectKeys(): Set<string>;
31
+ private readonly scopeManager;
32
+ private readonly expressionResolver;
33
+ private readonly callExpressionHandler;
34
+ private readonly jsxHandler;
35
+ /**
36
+ * Creates a new AST visitor instance.
37
+ *
38
+ * @param config - Toolkit configuration with extraction settings
39
+ * @param pluginContext - Context for adding discovered translation keys
40
+ * @param logger - Logger for warnings and debug information
41
+ */
42
+ constructor(config: Omit<I18nextToolkitConfig, 'plugins'>, pluginContext: PluginContext, logger: Logger, hooks?: ASTVisitorHooks);
43
+ /**
44
+ * Main entry point for AST traversal.
45
+ * Creates a root scope and begins the recursive walk through the syntax tree.
46
+ *
47
+ * @param node - The root module node to traverse
48
+ */
49
+ visit(node: Module): void;
50
+ /**
51
+ * Recursively walks through AST nodes, handling scoping and visiting logic.
52
+ *
53
+ * This is the core traversal method that:
54
+ * 1. Manages function scopes (enter/exit)
55
+ * 2. Dispatches to specific handlers based on node type
56
+ * 3. Recursively processes child nodes
57
+ * 4. Maintains proper scope cleanup
58
+ *
59
+ * @param node - The current AST node to process
60
+ *
61
+ * @private
62
+ */
63
+ private walk;
64
+ /**
65
+ * Retrieves variable information from the scope chain.
66
+ * Searches from innermost to outermost scope.
67
+ *
68
+ * @param name - Variable name to look up
69
+ * @returns Scope information if found, undefined otherwise
70
+ *
71
+ * @private
72
+ */
73
+ getVarFromScope(name: string): ScopeInfo | undefined;
74
+ }
75
+ //# sourceMappingURL=ast-visitors.d.ts.map
@@ -0,0 +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;AAM1G;;;;;;;;;;;;;;;;;;;;;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,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAuB;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IAEvC;;;;;;OAMG;gBAED,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,eAAe;IAkBzB;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IA2DZ;;;;;;;;OAQG;IACI,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;CAG7D"}
@@ -1,5 +1,5 @@
1
1
  import type { Logger, I18nextToolkitConfig, Plugin, PluginContext } from '../../types';
2
- import { ASTVisitors } from '../parsers/ast-visitors';
2
+ import { ASTVisitors } from './ast-visitors';
3
3
  /**
4
4
  * Main extractor function that runs the complete key extraction and file generation process.
5
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKtF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAKrD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,EACE,WAAmB,EACnB,QAAgB,EACjB,GAAE;IACD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,EACN,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,OAAO,CAAC,CAyDlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,OAAO,CAAE,MAAM,EAAE,oBAAoB,sDAO1D"}
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKtF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAK5C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,EACE,WAAmB,EACnB,QAAgB,EACjB,GAAE;IACD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,EACN,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,OAAO,CAAC,CAyDlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,OAAO,CAAE,MAAM,EAAE,oBAAoB,sDAO1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"key-finder.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/key-finder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAM7E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAgE1E"}
1
+ {"version":3,"file":"key-finder.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/key-finder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAmB,MAAM,aAAa,CAAA;AAM9F;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAgE1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"translation-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/translation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AA6MnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA8E9B"}
1
+ {"version":3,"file":"translation-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/translation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AA6RnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA8E9B"}
@@ -1,7 +1,7 @@
1
1
  export * from './core/extractor';
2
2
  export * from './core/key-finder';
3
3
  export * from './core/translation-manager';
4
- export * from './parsers/ast-visitors';
4
+ export * from './core/ast-visitors';
5
5
  export * from './parsers/comment-parser';
6
6
  export * from './parsers/jsx-parser';
7
7
  export * from './plugin-manager';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extractor/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extractor/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA"}
@@ -0,0 +1,74 @@
1
+ import type { CallExpression } from '@swc/core';
2
+ import type { PluginContext, I18nextToolkitConfig, Logger, ScopeInfo } from '../../types';
3
+ import { ExpressionResolver } from './expression-resolver';
4
+ export declare class CallExpressionHandler {
5
+ private pluginContext;
6
+ private config;
7
+ private logger;
8
+ private expressionResolver;
9
+ objectKeys: Set<string>;
10
+ constructor(config: Omit<I18nextToolkitConfig, 'plugins'>, pluginContext: PluginContext, logger: Logger, expressionResolver: ExpressionResolver);
11
+ /**
12
+ * Processes function call expressions to extract translation keys.
13
+ *
14
+ * This is the core extraction method that handles:
15
+ * - Standard t() calls with string literals
16
+ * - Selector API calls with arrow functions: `t($ => $.path.to.key)`
17
+ * - Namespace resolution from multiple sources
18
+ * - Default value extraction from various argument patterns
19
+ * - Pluralization and context handling
20
+ * - Key prefix application from scope
21
+ *
22
+ * @param node - Call expression node to process
23
+ * @param getScopeInfo - Function to retrieve scope information for variables
24
+ */
25
+ handleCallExpression(node: CallExpression, getScopeInfo: (name: string) => ScopeInfo | undefined): void;
26
+ /**
27
+ * Processed a call expression to extract keys from the specified argument.
28
+ *
29
+ * @param node - The call expression node
30
+ * @param argIndex - The index of the argument to process
31
+ * @returns An object containing the keys to process and a flag indicating if the selector API is used
32
+ */
33
+ private handleCallExpressionArgument;
34
+ /**
35
+ * Extracts translation key from selector API arrow function.
36
+ *
37
+ * Processes selector expressions like:
38
+ * - `$ => $.path.to.key` → 'path.to.key'
39
+ * - `$ => $.app['title'].main` → 'app.title.main'
40
+ * - `$ => { return $.nested.key; }` → 'nested.key'
41
+ *
42
+ * Handles both dot notation and bracket notation, respecting
43
+ * the configured key separator or flat key structure.
44
+ *
45
+ * @param node - Arrow function expression from selector call
46
+ * @returns Extracted key path or null if not statically analyzable
47
+ */
48
+ private extractKeyFromSelector;
49
+ /**
50
+ * Generates plural form keys based on the primary language's plural rules.
51
+ *
52
+ * Uses Intl.PluralRules to determine the correct plural categories
53
+ * for the configured primary language and generates suffixed keys
54
+ * for each category (e.g., 'item_one', 'item_other').
55
+ *
56
+ * @param key - Base key name for pluralization
57
+ * @param ns - Namespace for the keys
58
+ * @param options - object expression options
59
+ * @param isOrdinal - isOrdinal flag
60
+ */
61
+ private handlePluralKeys;
62
+ /**
63
+ * Serializes a callee node (Identifier or MemberExpression) into a string.
64
+ *
65
+ * Produces a dotted name for simple callees that can be used for scope lookups
66
+ * or configuration matching.
67
+ *
68
+ * @param callee - The CallExpression callee node to serialize
69
+ * @returns A dotted string name for supported callees, or null when the callee
70
+ * is a computed/unsupported expression.
71
+ */
72
+ private getFunctionName;
73
+ }
74
+ //# sourceMappingURL=call-expression-handler.d.ts.map
@@ -0,0 +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;AAG1D,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;gBAGnC,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB;IAQxC;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IAqMxG;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IA+HxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}