gtx-cli 2.5.0-alpha.2 → 2.5.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/CHANGELOG.md +23 -0
- package/dist/config/generateSettings.js +8 -1
- package/dist/console/colors.d.ts +1 -0
- package/dist/console/colors.js +3 -0
- package/dist/console/index.d.ts +8 -0
- package/dist/console/index.js +15 -2
- package/dist/react/jsx/evaluateJsx.d.ts +9 -6
- package/dist/react/jsx/evaluateJsx.js +33 -5
- package/dist/react/jsx/utils/buildImportMap.d.ts +9 -0
- package/dist/react/jsx/utils/buildImportMap.js +30 -0
- package/dist/react/jsx/utils/constants.d.ts +2 -0
- package/dist/react/jsx/utils/constants.js +11 -2
- package/dist/react/jsx/utils/getPathsAndAliases.d.ts +17 -0
- package/dist/react/jsx/utils/getPathsAndAliases.js +89 -0
- package/dist/react/{data-_gt → jsx/utils/jsxParsing}/addGTIdentifierToSyntaxTree.d.ts +2 -1
- package/dist/react/{data-_gt → jsx/utils/jsxParsing}/addGTIdentifierToSyntaxTree.js +30 -6
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.d.ts +6 -0
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.js +199 -0
- package/dist/react/jsx/utils/jsxParsing/multiplication/findMultiplicationNode.d.ts +13 -0
- package/dist/react/jsx/utils/jsxParsing/multiplication/findMultiplicationNode.js +42 -0
- package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.d.ts +5 -0
- package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.js +69 -0
- package/dist/react/jsx/utils/jsxParsing/parseJsx.d.ts +61 -0
- package/dist/react/jsx/utils/jsxParsing/parseJsx.js +1005 -0
- package/dist/react/jsx/utils/jsxParsing/parseTProps.d.ts +8 -0
- package/dist/react/jsx/utils/jsxParsing/parseTProps.js +47 -0
- package/dist/react/jsx/utils/jsxParsing/types.d.ts +48 -0
- package/dist/react/jsx/utils/jsxParsing/types.js +34 -0
- package/dist/react/jsx/utils/parseStringFunction.js +4 -141
- package/dist/react/jsx/utils/resolveImportPath.d.ts +11 -0
- package/dist/react/jsx/utils/resolveImportPath.js +111 -0
- package/dist/react/parse/createInlineUpdates.js +19 -70
- package/dist/workflow/SetupStep.js +0 -1
- package/package.json +2 -2
- package/dist/react/jsx/trimJsxStringChildren.d.ts +0 -7
- package/dist/react/jsx/trimJsxStringChildren.js +0 -122
- package/dist/react/jsx/utils/parseJsx.d.ts +0 -21
- package/dist/react/jsx/utils/parseJsx.js +0 -259
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Metadata } from 'generaltranslation/types';
|
|
2
|
+
import * as t from '@babel/types';
|
|
3
|
+
export declare function parseTProps({ openingElement, metadata, componentErrors, file, }: {
|
|
4
|
+
openingElement: t.JSXOpeningElement;
|
|
5
|
+
metadata: Metadata;
|
|
6
|
+
componentErrors: string[];
|
|
7
|
+
file: string;
|
|
8
|
+
}): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import generateModule from '@babel/generator';
|
|
3
|
+
// Handle CommonJS/ESM interop
|
|
4
|
+
const generate = generateModule.default || generateModule;
|
|
5
|
+
import { GT_ATTRIBUTES, mapAttributeName } from '../constants.js';
|
|
6
|
+
import { isStaticExpression } from '../../evaluateJsx.js';
|
|
7
|
+
import { warnVariablePropSync } from '../../../../console/index.js';
|
|
8
|
+
// Parse the props of a <T> component
|
|
9
|
+
export function parseTProps({ openingElement, metadata, componentErrors, file, }) {
|
|
10
|
+
openingElement.attributes.forEach((attr) => {
|
|
11
|
+
if (!t.isJSXAttribute(attr))
|
|
12
|
+
return;
|
|
13
|
+
const attrName = attr.name.name;
|
|
14
|
+
if (typeof attrName !== 'string')
|
|
15
|
+
return;
|
|
16
|
+
if (attr.value) {
|
|
17
|
+
// If it's a plain string literal like id="hello"
|
|
18
|
+
if (t.isStringLiteral(attr.value)) {
|
|
19
|
+
metadata[attrName] = attr.value.value;
|
|
20
|
+
}
|
|
21
|
+
// If it's an expression container like id={"hello"}, id={someVar}, etc.
|
|
22
|
+
else if (t.isJSXExpressionContainer(attr.value)) {
|
|
23
|
+
const expr = attr.value.expression;
|
|
24
|
+
const code = generate(expr).code;
|
|
25
|
+
// Only check for static expressions on id and context props
|
|
26
|
+
if (GT_ATTRIBUTES.includes(attrName)) {
|
|
27
|
+
const staticAnalysis = isStaticExpression(expr);
|
|
28
|
+
if (!staticAnalysis.isStatic) {
|
|
29
|
+
componentErrors.push(warnVariablePropSync(file, attrName, code, `${expr.loc?.start?.line}:${expr.loc?.start?.column}`));
|
|
30
|
+
}
|
|
31
|
+
// Use the static value if available
|
|
32
|
+
if (staticAnalysis.isStatic && staticAnalysis.value !== undefined) {
|
|
33
|
+
metadata[mapAttributeName(attrName)] = staticAnalysis.value;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Only store the code if we couldn't extract a static value
|
|
37
|
+
metadata[attrName] = code;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// For other attributes that aren't id or context
|
|
42
|
+
metadata[attrName] = code;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
type MultiplicationNode = {
|
|
2
|
+
nodeType: 'multiplication';
|
|
3
|
+
branches: (JsxTree | MultiplicationNode)[];
|
|
4
|
+
};
|
|
5
|
+
type ExpressionNode = {
|
|
6
|
+
nodeType: 'expression';
|
|
7
|
+
result: string | number | boolean | MultiplicationNode | null;
|
|
8
|
+
};
|
|
9
|
+
type ElementNode = {
|
|
10
|
+
nodeType: 'element';
|
|
11
|
+
type: string;
|
|
12
|
+
props?: {
|
|
13
|
+
children?: JsxTree | MultiplicationNode | (JsxTree | MultiplicationNode)[];
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
type JsxTree = ElementNode | ExpressionNode | string | number | boolean | null;
|
|
18
|
+
export type { MultiplicationNode, ExpressionNode, ElementNode, JsxTree };
|
|
19
|
+
declare function isElementNode(node: JsxTree | MultiplicationNode): node is ElementNode;
|
|
20
|
+
declare function isExpressionNode(node: JsxTree | MultiplicationNode): node is ExpressionNode;
|
|
21
|
+
declare function isMultiplicationNode(node: JsxTree | MultiplicationNode): node is MultiplicationNode;
|
|
22
|
+
export { isElementNode, isExpressionNode, isMultiplicationNode };
|
|
23
|
+
type WhitespaceMultiplicationNode = {
|
|
24
|
+
nodeType: 'multiplication';
|
|
25
|
+
branches: (WhitespaceJsxTreeResult | WhitespaceMultiplicationNode)[];
|
|
26
|
+
};
|
|
27
|
+
type WhitespaceJsxTree = {
|
|
28
|
+
nodeType?: 'element';
|
|
29
|
+
type: string;
|
|
30
|
+
props?: {
|
|
31
|
+
children?: (WhitespaceJsxTreeResult | WhitespaceMultiplicationNode)[];
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
type WhitespaceJsxTreeResult = WhitespaceJsxTree | string | number | boolean | null;
|
|
36
|
+
export type { WhitespaceMultiplicationNode, WhitespaceJsxTree, WhitespaceJsxTreeResult, };
|
|
37
|
+
declare function isWhitespaceJsxTree(node: WhitespaceJsxTreeResult | WhitespaceMultiplicationNode): node is WhitespaceJsxTree;
|
|
38
|
+
declare function isWhitespaceMultiplicationNode(node: WhitespaceJsxTreeResult | WhitespaceMultiplicationNode): node is WhitespaceMultiplicationNode;
|
|
39
|
+
export { isWhitespaceJsxTree, isWhitespaceMultiplicationNode };
|
|
40
|
+
type MultipliedTree = {
|
|
41
|
+
nodeType?: 'element';
|
|
42
|
+
type: string;
|
|
43
|
+
props?: {
|
|
44
|
+
children?: MultipliedTreeNode;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
type MultipliedTreeNode = MultipliedTree | string | number | boolean | null;
|
|
48
|
+
export type { MultipliedTree, MultipliedTreeNode };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ----- Helpers ----- //
|
|
2
|
+
function isElementNode(node) {
|
|
3
|
+
return (typeof node === 'object' &&
|
|
4
|
+
node !== null &&
|
|
5
|
+
'nodeType' in node &&
|
|
6
|
+
node.nodeType === 'element');
|
|
7
|
+
}
|
|
8
|
+
function isExpressionNode(node) {
|
|
9
|
+
return (typeof node === 'object' &&
|
|
10
|
+
node !== null &&
|
|
11
|
+
'nodeType' in node &&
|
|
12
|
+
node.nodeType === 'expression');
|
|
13
|
+
}
|
|
14
|
+
function isMultiplicationNode(node) {
|
|
15
|
+
return (typeof node === 'object' &&
|
|
16
|
+
node !== null &&
|
|
17
|
+
'nodeType' in node &&
|
|
18
|
+
node.nodeType === 'multiplication');
|
|
19
|
+
}
|
|
20
|
+
export { isElementNode, isExpressionNode, isMultiplicationNode };
|
|
21
|
+
// ----- Helpers ----- //
|
|
22
|
+
function isWhitespaceJsxTree(node) {
|
|
23
|
+
return (typeof node === 'object' &&
|
|
24
|
+
node !== null &&
|
|
25
|
+
'nodeType' in node &&
|
|
26
|
+
node.nodeType === 'element');
|
|
27
|
+
}
|
|
28
|
+
function isWhitespaceMultiplicationNode(node) {
|
|
29
|
+
return (typeof node === 'object' &&
|
|
30
|
+
node !== null &&
|
|
31
|
+
'nodeType' in node &&
|
|
32
|
+
node.nodeType === 'multiplication');
|
|
33
|
+
}
|
|
34
|
+
export { isWhitespaceJsxTree, isWhitespaceMultiplicationNode };
|
|
@@ -8,12 +8,9 @@ import traverseModule from '@babel/traverse';
|
|
|
8
8
|
const generate = generateModule.default || generateModule;
|
|
9
9
|
const traverse = traverseModule.default || traverseModule;
|
|
10
10
|
import fs from 'node:fs';
|
|
11
|
-
import path from 'node:path';
|
|
12
11
|
import { parse } from '@babel/parser';
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
15
|
-
import enhancedResolve from 'enhanced-resolve';
|
|
16
|
-
const { ResolverFactory } = enhancedResolve;
|
|
12
|
+
import { resolveImportPath } from './resolveImportPath.js';
|
|
13
|
+
import { buildImportMap } from './buildImportMap.js';
|
|
17
14
|
/**
|
|
18
15
|
* Cache for resolved import paths to avoid redundant I/O operations.
|
|
19
16
|
* Key: `${currentFile}::${importPath}`
|
|
@@ -112,35 +109,6 @@ function extractParameterName(param) {
|
|
|
112
109
|
}
|
|
113
110
|
return null;
|
|
114
111
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Builds a map of imported function names to their import paths from a given program path.
|
|
117
|
-
* Handles both named imports and default imports.
|
|
118
|
-
*
|
|
119
|
-
* Example: import { getInfo } from './constants' -> Map { 'getInfo' => './constants' }
|
|
120
|
-
* Example: import utils from './utils' -> Map { 'utils' => './utils' }
|
|
121
|
-
*/
|
|
122
|
-
function buildImportMap(programPath) {
|
|
123
|
-
const importMap = new Map();
|
|
124
|
-
programPath.traverse({
|
|
125
|
-
ImportDeclaration(importPath) {
|
|
126
|
-
if (t.isStringLiteral(importPath.node.source)) {
|
|
127
|
-
const importSource = importPath.node.source.value;
|
|
128
|
-
importPath.node.specifiers.forEach((spec) => {
|
|
129
|
-
if (t.isImportSpecifier(spec) &&
|
|
130
|
-
t.isIdentifier(spec.imported) &&
|
|
131
|
-
t.isIdentifier(spec.local)) {
|
|
132
|
-
importMap.set(spec.local.name, importSource);
|
|
133
|
-
}
|
|
134
|
-
else if (t.isImportDefaultSpecifier(spec) &&
|
|
135
|
-
t.isIdentifier(spec.local)) {
|
|
136
|
-
importMap.set(spec.local.name, importSource);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
return importMap;
|
|
143
|
-
}
|
|
144
112
|
/**
|
|
145
113
|
* Recursively resolves variable assignments to find all aliases of a translation callback parameter.
|
|
146
114
|
* Handles cases like: const t = translate; const a = translate; const b = a; const c = b;
|
|
@@ -212,7 +180,7 @@ function handleFunctionCall(tPath, updates, errors, warnings, file, importMap, i
|
|
|
212
180
|
// If not found locally, check if it's an imported function
|
|
213
181
|
else if (importMap.has(callee.name)) {
|
|
214
182
|
const importPath = importMap.get(callee.name);
|
|
215
|
-
const resolvedPath = resolveImportPath(file, importPath, parsingOptions);
|
|
183
|
+
const resolvedPath = resolveImportPath(file, importPath, parsingOptions, resolveImportPathCache);
|
|
216
184
|
if (resolvedPath) {
|
|
217
185
|
processFunctionInFile(resolvedPath, callee.name, argIndex, updates, errors, warnings, ignoreAdditionalData, ignoreDynamicContent, ignoreInvalidIcu, parsingOptions);
|
|
218
186
|
}
|
|
@@ -263,111 +231,6 @@ function findFunctionParameterUsage(functionPath, parameterName, updates, errors
|
|
|
263
231
|
});
|
|
264
232
|
}
|
|
265
233
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Resolves import paths to absolute file paths using battle-tested libraries.
|
|
268
|
-
* Handles relative paths, TypeScript paths, and node module resolution.
|
|
269
|
-
*
|
|
270
|
-
* Examples:
|
|
271
|
-
* - './constants' -> '/full/path/to/constants.ts'
|
|
272
|
-
* - '@/components/ui/button' -> '/full/path/to/src/components/ui/button.tsx'
|
|
273
|
-
* - '@shared/utils' -> '/full/path/to/packages/utils/index.ts'
|
|
274
|
-
*/
|
|
275
|
-
function resolveImportPath(currentFile, importPath, parsingOptions) {
|
|
276
|
-
// Check cache first
|
|
277
|
-
const cacheKey = `${currentFile}::${importPath}`;
|
|
278
|
-
if (resolveImportPathCache.has(cacheKey)) {
|
|
279
|
-
return resolveImportPathCache.get(cacheKey);
|
|
280
|
-
}
|
|
281
|
-
const basedir = path.dirname(currentFile);
|
|
282
|
-
const extensions = ['.tsx', '.ts', '.jsx', '.js'];
|
|
283
|
-
const mainFields = ['module', 'main'];
|
|
284
|
-
let result = null;
|
|
285
|
-
// 1. Try tsconfig-paths resolution first (handles TypeScript path mapping)
|
|
286
|
-
const tsConfigResult = loadConfig(basedir);
|
|
287
|
-
if (tsConfigResult.resultType === 'success') {
|
|
288
|
-
const matchPath = createMatchPath(tsConfigResult.absoluteBaseUrl, tsConfigResult.paths, mainFields);
|
|
289
|
-
// First try without any extension
|
|
290
|
-
let tsResolved = matchPath(importPath);
|
|
291
|
-
if (tsResolved && fs.existsSync(tsResolved)) {
|
|
292
|
-
result = tsResolved;
|
|
293
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
294
|
-
return result;
|
|
295
|
-
}
|
|
296
|
-
// Then try with each extension
|
|
297
|
-
for (const ext of extensions) {
|
|
298
|
-
tsResolved = matchPath(importPath + ext);
|
|
299
|
-
if (tsResolved && fs.existsSync(tsResolved)) {
|
|
300
|
-
result = tsResolved;
|
|
301
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
302
|
-
return result;
|
|
303
|
-
}
|
|
304
|
-
// Also try the resolved path with extension
|
|
305
|
-
tsResolved = matchPath(importPath);
|
|
306
|
-
if (tsResolved) {
|
|
307
|
-
const resolvedWithExt = tsResolved + ext;
|
|
308
|
-
if (fs.existsSync(resolvedWithExt)) {
|
|
309
|
-
result = resolvedWithExt;
|
|
310
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
311
|
-
return result;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
// 2. Try enhanced-resolve (handles package.json exports field and modern resolution)
|
|
317
|
-
try {
|
|
318
|
-
const resolver = ResolverFactory.createResolver({
|
|
319
|
-
useSyncFileSystemCalls: true,
|
|
320
|
-
fileSystem: fs,
|
|
321
|
-
extensions,
|
|
322
|
-
// Include 'development' condition to resolve to source files in monorepos
|
|
323
|
-
conditionNames: parsingOptions.conditionNames, // defaults to ['browser', 'module', 'import', 'require', 'default']. See generateSettings.ts for more details
|
|
324
|
-
exportsFields: ['exports'],
|
|
325
|
-
mainFields,
|
|
326
|
-
});
|
|
327
|
-
const resolved = resolver.resolveSync({}, basedir, importPath);
|
|
328
|
-
if (resolved) {
|
|
329
|
-
result = resolved;
|
|
330
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
331
|
-
return result;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
catch {
|
|
335
|
-
// Fall through to next resolution strategy
|
|
336
|
-
}
|
|
337
|
-
// 3. Fallback to Node.js resolution (handles relative paths and node_modules)
|
|
338
|
-
try {
|
|
339
|
-
result = resolve.sync(importPath, { basedir, extensions });
|
|
340
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
341
|
-
return result;
|
|
342
|
-
}
|
|
343
|
-
catch {
|
|
344
|
-
// If resolution fails, try to manually replace .js/.jsx with .ts/.tsx for source files
|
|
345
|
-
if (importPath.endsWith('.js')) {
|
|
346
|
-
const tsPath = importPath.replace(/\.js$/, '.ts');
|
|
347
|
-
try {
|
|
348
|
-
result = resolve.sync(tsPath, { basedir, extensions });
|
|
349
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
350
|
-
return result;
|
|
351
|
-
}
|
|
352
|
-
catch {
|
|
353
|
-
// Continue to return null
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
else if (importPath.endsWith('.jsx')) {
|
|
357
|
-
const tsxPath = importPath.replace(/\.jsx$/, '.tsx');
|
|
358
|
-
try {
|
|
359
|
-
result = resolve.sync(tsxPath, { basedir, extensions });
|
|
360
|
-
resolveImportPathCache.set(cacheKey, result);
|
|
361
|
-
return result;
|
|
362
|
-
}
|
|
363
|
-
catch {
|
|
364
|
-
// Continue to return null
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
resolveImportPathCache.set(cacheKey, null);
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
234
|
/**
|
|
372
235
|
* Searches for a specific user-defined function in a file and analyzes how a translation callback
|
|
373
236
|
* parameter (at argIndex position) is used within that function.
|
|
@@ -446,7 +309,7 @@ function processFunctionInFile(filePath, functionName, argIndex, updates, errors
|
|
|
446
309
|
// If function not found, follow re-exports
|
|
447
310
|
if (!found && reExports.length > 0) {
|
|
448
311
|
for (const reExportPath of reExports) {
|
|
449
|
-
const resolvedPath = resolveImportPath(filePath, reExportPath, parsingOptions);
|
|
312
|
+
const resolvedPath = resolveImportPath(filePath, reExportPath, parsingOptions, resolveImportPathCache);
|
|
450
313
|
if (resolvedPath) {
|
|
451
314
|
processFunctionInFile(resolvedPath, functionName, argIndex, updates, errors, warnings, ignoreAdditionalData, ignoreDynamicContent, ignoreInvalidIcu, parsingOptions, visited);
|
|
452
315
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ParsingConfigOptions } from '../../../types/parsing.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves import paths to absolute file paths using battle-tested libraries.
|
|
4
|
+
* Handles relative paths, TypeScript paths, and node module resolution.
|
|
5
|
+
*
|
|
6
|
+
* Examples:
|
|
7
|
+
* - './constants' -> '/full/path/to/constants.ts'
|
|
8
|
+
* - '@/components/ui/button' -> '/full/path/to/src/components/ui/button.tsx'
|
|
9
|
+
* - '@shared/utils' -> '/full/path/to/packages/utils/index.ts'
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveImportPath(currentFile: string, importPath: string, parsingOptions: ParsingConfigOptions, resolveImportPathCache: Map<string, string | null>): string | null;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createMatchPath, loadConfig } from 'tsconfig-paths';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import resolve from 'resolve';
|
|
5
|
+
import enhancedResolve from 'enhanced-resolve';
|
|
6
|
+
const { ResolverFactory } = enhancedResolve;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves import paths to absolute file paths using battle-tested libraries.
|
|
9
|
+
* Handles relative paths, TypeScript paths, and node module resolution.
|
|
10
|
+
*
|
|
11
|
+
* Examples:
|
|
12
|
+
* - './constants' -> '/full/path/to/constants.ts'
|
|
13
|
+
* - '@/components/ui/button' -> '/full/path/to/src/components/ui/button.tsx'
|
|
14
|
+
* - '@shared/utils' -> '/full/path/to/packages/utils/index.ts'
|
|
15
|
+
*/
|
|
16
|
+
export function resolveImportPath(currentFile, importPath, parsingOptions, resolveImportPathCache) {
|
|
17
|
+
// Check cache first
|
|
18
|
+
const cacheKey = `${currentFile}::${importPath}`;
|
|
19
|
+
if (resolveImportPathCache.has(cacheKey)) {
|
|
20
|
+
return resolveImportPathCache.get(cacheKey);
|
|
21
|
+
}
|
|
22
|
+
const basedir = path.dirname(currentFile);
|
|
23
|
+
const extensions = ['.tsx', '.ts', '.jsx', '.js'];
|
|
24
|
+
const mainFields = ['module', 'main'];
|
|
25
|
+
let result = null;
|
|
26
|
+
// 1. Try tsconfig-paths resolution first (handles TypeScript path mapping)
|
|
27
|
+
const tsConfigResult = loadConfig(basedir);
|
|
28
|
+
if (tsConfigResult.resultType === 'success') {
|
|
29
|
+
const matchPath = createMatchPath(tsConfigResult.absoluteBaseUrl, tsConfigResult.paths, mainFields);
|
|
30
|
+
// First try without any extension
|
|
31
|
+
let tsResolved = matchPath(importPath);
|
|
32
|
+
if (tsResolved && fs.existsSync(tsResolved)) {
|
|
33
|
+
result = tsResolved;
|
|
34
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
// Then try with each extension
|
|
38
|
+
for (const ext of extensions) {
|
|
39
|
+
tsResolved = matchPath(importPath + ext);
|
|
40
|
+
if (tsResolved && fs.existsSync(tsResolved)) {
|
|
41
|
+
result = tsResolved;
|
|
42
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
// Also try the resolved path with extension
|
|
46
|
+
tsResolved = matchPath(importPath);
|
|
47
|
+
if (tsResolved) {
|
|
48
|
+
const resolvedWithExt = tsResolved + ext;
|
|
49
|
+
if (fs.existsSync(resolvedWithExt)) {
|
|
50
|
+
result = resolvedWithExt;
|
|
51
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 2. Try enhanced-resolve (handles package.json exports field and modern resolution)
|
|
58
|
+
try {
|
|
59
|
+
const resolver = ResolverFactory.createResolver({
|
|
60
|
+
useSyncFileSystemCalls: true,
|
|
61
|
+
fileSystem: fs,
|
|
62
|
+
extensions,
|
|
63
|
+
// Include 'development' condition to resolve to source files in monorepos
|
|
64
|
+
conditionNames: parsingOptions.conditionNames, // defaults to ['browser', 'module', 'import', 'require', 'default']. See generateSettings.ts for more details
|
|
65
|
+
exportsFields: ['exports'],
|
|
66
|
+
mainFields,
|
|
67
|
+
});
|
|
68
|
+
const resolved = resolver.resolveSync({}, basedir, importPath);
|
|
69
|
+
if (resolved) {
|
|
70
|
+
result = resolved;
|
|
71
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Fall through to next resolution strategy
|
|
77
|
+
}
|
|
78
|
+
// 3. Fallback to Node.js resolution (handles relative paths and node_modules)
|
|
79
|
+
try {
|
|
80
|
+
result = resolve.sync(importPath, { basedir, extensions });
|
|
81
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// If resolution fails, try to manually replace .js/.jsx with .ts/.tsx for source files
|
|
86
|
+
if (importPath.endsWith('.js')) {
|
|
87
|
+
const tsPath = importPath.replace(/\.js$/, '.ts');
|
|
88
|
+
try {
|
|
89
|
+
result = resolve.sync(tsPath, { basedir, extensions });
|
|
90
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Continue to return null
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (importPath.endsWith('.jsx')) {
|
|
98
|
+
const tsxPath = importPath.replace(/\.jsx$/, '.tsx');
|
|
99
|
+
try {
|
|
100
|
+
result = resolve.sync(tsxPath, { basedir, extensions });
|
|
101
|
+
resolveImportPathCache.set(cacheKey, result);
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Continue to return null
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
resolveImportPathCache.set(cacheKey, null);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { parse } from '@babel/parser';
|
|
3
|
-
import traverseModule from '@babel/traverse';
|
|
4
|
-
// Handle CommonJS/ESM interop
|
|
5
|
-
const traverse = traverseModule.default || traverseModule;
|
|
6
3
|
import { hashSource } from 'generaltranslation/id';
|
|
7
|
-
import {
|
|
4
|
+
import { parseTranslationComponent } from '../jsx/utils/jsxParsing/parseJsx.js';
|
|
8
5
|
import { parseStrings } from '../jsx/utils/parseStringFunction.js';
|
|
9
|
-
import { extractImportName } from '../jsx/utils/parseAst.js';
|
|
10
6
|
import { logError } from '../../console/logging.js';
|
|
11
|
-
import { GT_TRANSLATION_FUNCS, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, MSG_TRANSLATION_HOOK, } from '../jsx/utils/constants.js';
|
|
12
7
|
import { matchFiles } from '../../fs/matchFiles.js';
|
|
13
8
|
import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
|
|
9
|
+
import { getPathsAndAliases } from '../jsx/utils/getPathsAndAliases.js';
|
|
14
10
|
export async function createInlineUpdates(pkg, validate, filePatterns, parsingOptions) {
|
|
15
11
|
const updates = [];
|
|
16
12
|
const errors = [];
|
|
@@ -30,75 +26,28 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
|
|
|
30
26
|
logError(`Error parsing file ${file}: ${error}`);
|
|
31
27
|
continue;
|
|
32
28
|
}
|
|
33
|
-
const importAliases = {};
|
|
34
29
|
// First pass: collect imports and process translation functions
|
|
35
|
-
const
|
|
36
|
-
traverse(ast, {
|
|
37
|
-
ImportDeclaration(path) {
|
|
38
|
-
if (path.node.source.value.startsWith(pkg)) {
|
|
39
|
-
const importName = extractImportName(path.node, pkg, GT_TRANSLATION_FUNCS);
|
|
40
|
-
for (const name of importName) {
|
|
41
|
-
if (name.original === INLINE_TRANSLATION_HOOK ||
|
|
42
|
-
name.original === INLINE_TRANSLATION_HOOK_ASYNC ||
|
|
43
|
-
name.original === INLINE_MESSAGE_HOOK ||
|
|
44
|
-
name.original === INLINE_MESSAGE_HOOK_ASYNC ||
|
|
45
|
-
name.original === MSG_TRANSLATION_HOOK) {
|
|
46
|
-
translationPaths.push({
|
|
47
|
-
localName: name.local,
|
|
48
|
-
path,
|
|
49
|
-
originalName: name.original,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
importAliases[name.local] = name.original;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
VariableDeclarator(path) {
|
|
59
|
-
// Check if the init is a require call
|
|
60
|
-
if (path.node.init?.type === 'CallExpression' &&
|
|
61
|
-
path.node.init.callee.type === 'Identifier' &&
|
|
62
|
-
path.node.init.callee.name === 'require') {
|
|
63
|
-
// Check if it's requiring our package
|
|
64
|
-
const args = path.node.init.arguments;
|
|
65
|
-
if (args.length === 1 &&
|
|
66
|
-
args[0].type === 'StringLiteral' &&
|
|
67
|
-
args[0].value.startsWith(pkg)) {
|
|
68
|
-
const parentPath = path.parentPath;
|
|
69
|
-
if (parentPath.isVariableDeclaration()) {
|
|
70
|
-
const importName = extractImportName(parentPath.node, pkg, GT_TRANSLATION_FUNCS);
|
|
71
|
-
for (const name of importName) {
|
|
72
|
-
if (name.original === INLINE_TRANSLATION_HOOK ||
|
|
73
|
-
name.original === INLINE_TRANSLATION_HOOK_ASYNC ||
|
|
74
|
-
name.original === INLINE_MESSAGE_HOOK ||
|
|
75
|
-
name.original === INLINE_MESSAGE_HOOK_ASYNC ||
|
|
76
|
-
name.original === MSG_TRANSLATION_HOOK) {
|
|
77
|
-
translationPaths.push({
|
|
78
|
-
localName: name.local,
|
|
79
|
-
path: parentPath,
|
|
80
|
-
originalName: name.original,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
importAliases[name.local] = name.original;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
});
|
|
30
|
+
const { importAliases, inlineTranslationPaths, translationComponentPaths } = getPathsAndAliases(ast, pkg);
|
|
92
31
|
// Process translation functions asynchronously
|
|
93
|
-
for (const { localName: name, originalName, path } of
|
|
32
|
+
for (const { localName: name, originalName, path, } of inlineTranslationPaths) {
|
|
94
33
|
parseStrings(name, originalName, path, updates, errors, warnings, file, parsingOptions);
|
|
95
34
|
}
|
|
96
35
|
// Parse <T> components
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
36
|
+
for (const { localName, path } of translationComponentPaths) {
|
|
37
|
+
parseTranslationComponent({
|
|
38
|
+
importAliases: importAliases,
|
|
39
|
+
originalName: localName,
|
|
40
|
+
localName,
|
|
41
|
+
ast,
|
|
42
|
+
pkg,
|
|
43
|
+
path,
|
|
44
|
+
updates,
|
|
45
|
+
errors,
|
|
46
|
+
warnings,
|
|
47
|
+
file,
|
|
48
|
+
parsingOptions,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
102
51
|
// Extra validation (for Locadex)
|
|
103
52
|
// Done in parseStrings() atm
|
|
104
53
|
// if (validate) {
|
|
@@ -51,7 +51,6 @@ export class SetupStep extends WorkflowStep {
|
|
|
51
51
|
const pollInterval = 5000; // 5 seconds
|
|
52
52
|
while (Date.now() - start < this.timeoutMs) {
|
|
53
53
|
const status = await this.gt.checkJobStatus([this.setupJobId]);
|
|
54
|
-
console.log(status);
|
|
55
54
|
if (!status[0]) {
|
|
56
55
|
this.spinner.stop(chalk.yellow('Setup status unknown — proceeding without setup'));
|
|
57
56
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtx-cli",
|
|
3
|
-
"version": "2.5.0
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "dist/main.js",
|
|
6
6
|
"files": [
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"unified": "^11.0.5",
|
|
94
94
|
"unist-util-visit": "^5.0.0",
|
|
95
95
|
"yaml": "^2.8.0",
|
|
96
|
-
"generaltranslation": "8.0.0
|
|
96
|
+
"generaltranslation": "8.0.0"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"@babel/types": "^7.28.4",
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare function trimJsxStringChild(child: string, index: number, childrenTypes: ('expression' | 'text' | 'element')[]): string;
|
|
2
|
-
/**
|
|
3
|
-
* Handles whitespace in children of a JSX element.
|
|
4
|
-
* @param currentTree - The current tree to handle
|
|
5
|
-
* @returns The processed tree with whitespace handled
|
|
6
|
-
*/
|
|
7
|
-
export declare const handleChildrenWhitespace: (currentTree: any) => any;
|