gt 2.14.4 → 2.14.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.14.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1174](https://github.com/generaltranslation/gt/pull/1174) [`4730814`](https://github.com/generaltranslation/gt/commit/4730814799ba5487b45477094c6ca581ac56c3ff) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - fix: recursive string translation function resolution
8
+
3
9
  ## 2.14.4
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.14.4";
1
+ export declare const PACKAGE_VERSION = "2.14.5";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.14.4';
2
+ export const PACKAGE_VERSION = '2.14.5';
@@ -83,7 +83,7 @@ export function resolveVariableAliases(scope, variableName, visited = new Set())
83
83
  * This covers both direct translation calls (gt('hello')) and prop drilling
84
84
  * where the translation callback is passed to other functions (getData(gt)).
85
85
  */
86
- function handleFunctionCall(tPath, config, state, output) {
86
+ function handleFunctionCall(tPath, config, state, output, visitedFunctions) {
87
87
  if (tPath.parent.type === 'CallExpression' &&
88
88
  tPath.parent.callee === tPath.node) {
89
89
  // Direct translation call: t('hello')
@@ -105,7 +105,7 @@ function handleFunctionCall(tPath, config, state, output) {
105
105
  const calleeBinding = tPath.scope.getBinding(callee.name);
106
106
  if (calleeBinding && calleeBinding.path.isFunction()) {
107
107
  const functionPath = calleeBinding.path;
108
- processFunctionIfMatches(callee.name, argIndex, functionPath.node, functionPath, config, output);
108
+ processFunctionIfMatches(callee.name, argIndex, functionPath.node, functionPath, config, output, visitedFunctions);
109
109
  }
110
110
  // Handle arrow functions assigned to variables: const getData = (t) => {...}
111
111
  else if (calleeBinding &&
@@ -114,7 +114,7 @@ function handleFunctionCall(tPath, config, state, output) {
114
114
  (t.isArrowFunctionExpression(calleeBinding.path.node.init) ||
115
115
  t.isFunctionExpression(calleeBinding.path.node.init))) {
116
116
  const initPath = calleeBinding.path.get('init');
117
- processFunctionIfMatches(callee.name, argIndex, calleeBinding.path.node.init, initPath, config, output);
117
+ processFunctionIfMatches(callee.name, argIndex, calleeBinding.path.node.init, initPath, config, output, visitedFunctions);
118
118
  }
119
119
  // If not found locally, check if it's an imported function
120
120
  else if (state.importMap.has(callee.name)) {
@@ -132,14 +132,18 @@ function handleFunctionCall(tPath, config, state, output) {
132
132
  * Validates the function has enough parameters and traces how the translation callback
133
133
  * is used within that function's body.
134
134
  */
135
- function processFunctionIfMatches(_functionName, argIndex, functionNode, functionPath, config, output) {
135
+ function processFunctionIfMatches(_functionName, argIndex, functionNode, functionPath, config, output, visitedFunctions) {
136
+ if (visitedFunctions.has(functionNode))
137
+ return;
138
+ visitedFunctions.add(functionNode);
136
139
  if (functionNode.params.length > argIndex) {
137
140
  const param = functionNode.params[argIndex];
138
141
  const paramName = extractParameterName(param);
139
142
  if (paramName) {
140
- findFunctionParameterUsage(functionPath, paramName, config, output);
143
+ findFunctionParameterUsage(functionPath, paramName, config, output, visitedFunctions);
141
144
  }
142
145
  }
146
+ visitedFunctions.delete(functionNode);
143
147
  }
144
148
  /**
145
149
  * Finds all usages of a translation callback parameter within a user-defined function's scope.
@@ -149,7 +153,7 @@ function processFunctionIfMatches(_functionName, argIndex, functionNode, functio
149
153
  * Example: In function getInfo(t) { return t('hello'); }, this finds the t('hello') call.
150
154
  * Example: In function getData(t) { return getFooter(t); }, this finds and traces into getFooter.
151
155
  */
152
- function findFunctionParameterUsage(functionPath, parameterName, config, output) {
156
+ function findFunctionParameterUsage(functionPath, parameterName, config, output, visitedFunctions) {
153
157
  // Look for the function body and find all usages of the parameter
154
158
  if (functionPath.isFunction()) {
155
159
  const functionScope = functionPath.scope;
@@ -164,7 +168,7 @@ function findFunctionParameterUsage(functionPath, parameterName, config, output)
164
168
  const binding = functionScope.bindings[name];
165
169
  if (binding) {
166
170
  binding.referencePaths.forEach((refPath) => {
167
- handleFunctionCall(refPath, config, { visited: new Set(), importMap }, output);
171
+ handleFunctionCall(refPath, config, { visited: new Set(), importMap }, output, visitedFunctions);
168
172
  });
169
173
  }
170
174
  });
@@ -200,12 +204,15 @@ function processFunctionInFile(filePath, functionName, argIndex, config, state,
200
204
  });
201
205
  let found = false;
202
206
  const reExports = [];
207
+ // Fresh set per cross-file parse — node identity is only stable within a single parse.
208
+ // Cross-file cycles are already guarded by processFunctionCache above.
209
+ const visitedFunctions = new Set();
203
210
  traverse(ast, {
204
211
  // Handle function declarations: function getInfo(t) { ... }
205
212
  FunctionDeclaration(path) {
206
213
  if (path.node.id?.name === functionName) {
207
214
  found = true;
208
- processFunctionIfMatches(functionName, argIndex, path.node, path, config, output);
215
+ processFunctionIfMatches(functionName, argIndex, path.node, path, config, output, visitedFunctions);
209
216
  }
210
217
  },
211
218
  // Handle variable declarations: const getInfo = (t) => { ... }
@@ -217,7 +224,7 @@ function processFunctionInFile(filePath, functionName, argIndex, config, state,
217
224
  t.isFunctionExpression(path.node.init))) {
218
225
  found = true;
219
226
  const initPath = path.get('init');
220
- processFunctionIfMatches(functionName, argIndex, path.node.init, initPath, config, output);
227
+ processFunctionIfMatches(functionName, argIndex, path.node.init, initPath, config, output, visitedFunctions);
221
228
  }
222
229
  },
223
230
  // Collect re-exports: export * from './other'
@@ -401,10 +408,11 @@ export function parseStrings(importName, originalName, path, config, output) {
401
408
  // Example: translate -> [translate, t, a, b] for const t = translate; const a = t; const b = a;
402
409
  const allTranslationNames = resolveVariableAliases(variableScope, tFuncName);
403
410
  // Process references for all translation function names and their aliases
411
+ const visitedFunctions = new Set();
404
412
  allTranslationNames.forEach((name) => {
405
413
  const tReferencePaths = variableScope.bindings[name]?.referencePaths || [];
406
414
  for (const tPath of tReferencePaths) {
407
- handleFunctionCall(tPath, hookConfig, { visited: new Set(), importMap }, output);
415
+ handleFunctionCall(tPath, hookConfig, { visited: new Set(), importMap }, output, visitedFunctions);
408
416
  }
409
417
  });
410
418
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.14.4",
3
+ "version": "2.14.5",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -111,8 +111,8 @@
111
111
  "unist-util-visit": "^5.0.0",
112
112
  "yaml": "^2.8.0",
113
113
  "@generaltranslation/python-extractor": "0.2.6",
114
- "generaltranslation": "8.2.2",
115
- "gt-remark": "1.0.7"
114
+ "gt-remark": "1.0.7",
115
+ "generaltranslation": "8.2.2"
116
116
  },
117
117
  "devDependencies": {
118
118
  "@babel/types": "^7.28.4",