gtx-cli 1.0.0-alpha.2 → 1.0.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/cli/next.js CHANGED
@@ -19,8 +19,8 @@ const prompts_1 = require("@inquirer/prompts");
19
19
  const postProcess_1 = require("../hooks/postProcess");
20
20
  const findFilepath_1 = __importDefault(require("../fs/findFilepath"));
21
21
  const scanForContent_1 = __importDefault(require("../next/parse/scanForContent"));
22
- const createDictionaryUpdates_1 = __importDefault(require("../react/updates/createDictionaryUpdates"));
23
- const createInlineUpdates_1 = __importDefault(require("../react/updates/createInlineUpdates"));
22
+ const createDictionaryUpdates_1 = __importDefault(require("../react/parse/createDictionaryUpdates"));
23
+ const createInlineUpdates_1 = __importDefault(require("../react/parse/createInlineUpdates"));
24
24
  const handleInitGT_1 = __importDefault(require("../next/parse/handleInitGT"));
25
25
  const react_1 = require("./react");
26
26
  const generateSettings_1 = require("../config/generateSettings");
package/dist/cli/react.js CHANGED
@@ -121,14 +121,7 @@ class ReactCLI extends base_1.BaseCLI {
121
121
  .description('Generate a translation file for the source locale. The -t flag must be provided. This command should be used if you are handling your own translations.')
122
122
  .option('--src <paths...>', "Filepath to directory containing the app's source code, by default ./src || ./app || ./pages || ./components", (0, findFilepath_1.findFilepaths)(['./src', './app', './pages', './components']))
123
123
  .option('--tsconfig, --jsconfig <path>', 'Path to jsconfig or tsconfig file', (0, findFilepath_1.default)(['./tsconfig.json', './jsconfig.json']))
124
- .option('--dictionary <path>', 'Path to dictionary file', (0, findFilepath_1.default)([
125
- './dictionary.js',
126
- './src/dictionary.js',
127
- './dictionary.json',
128
- './src/dictionary.json',
129
- './dictionary.ts',
130
- './src/dictionary.ts',
131
- ]))
124
+ .option('--dictionary <path>', 'Path to dictionary file')
132
125
  .option('--default-language, --default-locale <locale>', 'Source locale (e.g., en)', 'en')
133
126
  .option('--inline', 'Include inline <T> tags in addition to dictionary file', true)
134
127
  .option('--ignore-errors', 'Ignore errors encountered while scanning for <T> tags', false)
@@ -157,8 +150,19 @@ class ReactCLI extends base_1.BaseCLI {
157
150
  return __awaiter(this, void 0, void 0, function* () {
158
151
  (0, console_1.displayAsciiTitle)();
159
152
  (0, console_1.displayInitializingText)();
160
- const { updates, errors } = yield this.createUpdates(options);
161
153
  const settings = (0, generateSettings_1.generateSettings)(options);
154
+ options = Object.assign(Object.assign({}, options), settings);
155
+ if (!options.dictionary) {
156
+ options.dictionary = (0, findFilepath_1.default)([
157
+ './dictionary.js',
158
+ './src/dictionary.js',
159
+ './dictionary.json',
160
+ './src/dictionary.json',
161
+ './dictionary.ts',
162
+ './src/dictionary.ts',
163
+ ]);
164
+ }
165
+ const { updates, errors } = yield this.createUpdates(options);
162
166
  if (errors.length > 0) {
163
167
  if (options.ignoreErrors) {
164
168
  console.log(chalk_1.default.red(`CLI tool encountered errors while scanning for ${chalk_1.default.green('<T>')} tags.\n`));
@@ -438,11 +442,13 @@ class ReactCLI extends base_1.BaseCLI {
438
442
  // {defaultLocale}.json file exists in the translationsDir, and use that as a source
439
443
  // instead
440
444
  const sourceFile = (0, findFilepath_1.findFileInDir)(options.translationsDir, `${options.defaultLocale}.json`);
441
- options.dictionary = sourceFile;
442
- updates = [
443
- ...updates,
444
- ...(yield this.createDictionaryUpdates(options, (0, createESBuildConfig_1.default)({}))),
445
- ];
445
+ if (sourceFile) {
446
+ options.dictionary = sourceFile;
447
+ updates = [
448
+ ...updates,
449
+ ...(yield this.createDictionaryUpdates(options, (0, createESBuildConfig_1.default)({}))),
450
+ ];
451
+ }
446
452
  }
447
453
  // Scan through project for <T> tags
448
454
  if (options.inline) {
@@ -41,7 +41,7 @@ function translateJson(sourceJson, settings, dataFormat, fileExtension) {
41
41
  id,
42
42
  };
43
43
  updates.push({
44
- type: dataFormat,
44
+ dataFormat,
45
45
  source,
46
46
  metadata,
47
47
  });
@@ -58,7 +58,7 @@ function getRelativePath(file, srcDirectory) {
58
58
  function findFile(filePattern, file) {
59
59
  // Handle wildcard pattern by replacing the wildcard with the file parameter
60
60
  const resolvedPath = filePattern.replace(/\*/, file);
61
- if (fs_1.default.existsSync(resolvedPath)) {
61
+ if (fs_1.default.existsSync(resolvedPath) && fs_1.default.statSync(resolvedPath).isFile()) {
62
62
  return fs_1.default.readFileSync(resolvedPath, 'utf8');
63
63
  }
64
64
  return '';
@@ -71,8 +71,13 @@ function findFile(filePattern, file) {
71
71
  */
72
72
  function findFileInDir(dir, file) {
73
73
  const resolvedPath = path_1.default.join(dir, file);
74
- if (fs_1.default.existsSync(resolvedPath)) {
75
- return fs_1.default.readFileSync(resolvedPath, 'utf8');
74
+ try {
75
+ if (fs_1.default.existsSync(resolvedPath)) {
76
+ return fs_1.default.readFileSync(resolvedPath, 'utf8');
77
+ }
78
+ }
79
+ catch (error) {
80
+ console.error(error);
76
81
  }
77
82
  return '';
78
83
  }
@@ -103,7 +103,7 @@ function parseStrings(importName, path, updates, errors, file) {
103
103
  });
104
104
  }
105
105
  updates.push({
106
- type: 'JSX',
106
+ dataFormat: 'JSX',
107
107
  source: content,
108
108
  metadata,
109
109
  });
@@ -228,7 +228,7 @@ function parseJSXElement(importAliases, node, updates, errors, file) {
228
228
  // <T> is valid here
229
229
  // displayFoundTMessage(file, id);
230
230
  updates.push({
231
- type: 'JSX',
231
+ dataFormat: 'JSX',
232
232
  source: componentObj.tree,
233
233
  metadata: componentObj.props,
234
234
  });
@@ -103,7 +103,7 @@ function parseStrings(importName, path, updates, errors, file) {
103
103
  });
104
104
  }
105
105
  updates.push({
106
- type: 'JSX',
106
+ dataFormat: 'JSX',
107
107
  source: content,
108
108
  metadata,
109
109
  });
@@ -65,9 +65,9 @@ function createDictionaryUpdates(options, esbuildConfig) {
65
65
  const context = props === null || props === void 0 ? void 0 : props.context;
66
66
  const metadata = Object.assign(Object.assign({ id }, (context && { context })), {
67
67
  // This hash isn't actually used by the GT API, just for consistency sake
68
- hash: (0, id_1.hashJsxChildren)(Object.assign(Object.assign({ source }, (context && { context })), (id && { id }))) });
68
+ hash: (0, id_1.hashJsxChildren)(Object.assign(Object.assign(Object.assign({ source }, (context && { context })), (id && { id })), { dataFormat: 'JSX' })) });
69
69
  updates.push({
70
- type: 'JSX',
70
+ dataFormat: 'JSX',
71
71
  source,
72
72
  metadata,
73
73
  });
@@ -133,7 +133,7 @@ function createInlineUpdates(options, pkg) {
133
133
  // Post-process to add a hash to each update
134
134
  yield Promise.all(updates.map((update) => __awaiter(this, void 0, void 0, function* () {
135
135
  const context = update.metadata.context;
136
- const hash = (0, id_1.hashJsxChildren)(Object.assign(Object.assign({ source: update.source }, (context && { context })), (update.metadata.id && { id: update.metadata.id })));
136
+ const hash = (0, id_1.hashJsxChildren)(Object.assign(Object.assign(Object.assign({ source: update.source }, (context && { context })), (update.metadata.id && { id: update.metadata.id })), { dataFormat: 'JSX' }));
137
137
  update.metadata.hash = hash;
138
138
  })));
139
139
  return { updates, errors };
@@ -2,13 +2,13 @@ import { JsxChildren } from 'generaltranslation/internal';
2
2
  export type Updates = ({
3
3
  metadata: Record<string, any>;
4
4
  } & ({
5
- type: 'JSX';
5
+ dataFormat: 'JSX';
6
6
  source: JsxChildren;
7
7
  } | {
8
- type: 'ICU';
8
+ dataFormat: 'ICU';
9
9
  source: string;
10
10
  } | {
11
- type: 'I18NEXT';
11
+ dataFormat: 'I18NEXT';
12
12
  source: string;
13
13
  }))[];
14
14
  export type Options = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "scripts": {
@@ -52,9 +52,9 @@
52
52
  "commander": "^12.1.0",
53
53
  "dotenv": "^16.4.5",
54
54
  "esbuild": "^0.23.1",
55
- "generaltranslation": "^6.2.1-alpha.1",
56
- "js-yaml": "^4.1.0",
57
- "ora": "^8.2.0"
55
+ "generaltranslation": "^6.2.1",
56
+ "ora": "^8.2.0",
57
+ "yaml": "^2.7.0"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@biomejs/biome": "1.9.4",
@@ -1,5 +0,0 @@
1
- import { BuildOptions } from 'esbuild';
2
- import { Options, Updates } from '../../types';
3
- export default function createDictionaryUpdates(options: Options & {
4
- dictionary: string;
5
- }, esbuildConfig: BuildOptions): Promise<Updates>;
@@ -1,76 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.default = createDictionaryUpdates;
16
- const react_1 = __importDefault(require("react"));
17
- const fs_1 = __importDefault(require("fs"));
18
- const path_1 = __importDefault(require("path"));
19
- const os_1 = __importDefault(require("os"));
20
- const esbuild_1 = require("esbuild");
21
- const internal_1 = require("gt-react/internal");
22
- const generaltranslation_1 = require("generaltranslation");
23
- const loadJSON_1 = __importDefault(require("../../fs/loadJSON"));
24
- const id_1 = require("generaltranslation/id");
25
- function createDictionaryUpdates(options, esbuildConfig) {
26
- return __awaiter(this, void 0, void 0, function* () {
27
- let dictionary;
28
- // ---- HANDLE JSON STRING DICTIONARY ----- //
29
- if (options.dictionary.endsWith('.json')) {
30
- dictionary = (0, internal_1.flattenDictionary)((0, loadJSON_1.default)(options.dictionary) || {});
31
- }
32
- // ----- HANDLE REACT DICTIONARY ---- //
33
- else {
34
- const result = yield (0, esbuild_1.build)(Object.assign(Object.assign({}, esbuildConfig), { entryPoints: [options.dictionary], write: false }));
35
- const bundledCode = result.outputFiles[0].text;
36
- const tempFilePath = path_1.default.join(os_1.default.tmpdir(), 'bundled-dictionary.js');
37
- fs_1.default.writeFileSync(tempFilePath, bundledCode);
38
- globalThis.React = react_1.default;
39
- // Load the module using require
40
- let dictionaryModule;
41
- try {
42
- dictionaryModule = require(tempFilePath);
43
- }
44
- catch (error) {
45
- console.error(`Failed to load the bundled dictionary code:`, error);
46
- process.exit(1);
47
- }
48
- finally {
49
- // Clean up the temporary file
50
- fs_1.default.unlinkSync(tempFilePath);
51
- }
52
- dictionary = (0, internal_1.flattenDictionary)(dictionaryModule.default ||
53
- dictionaryModule.dictionary ||
54
- dictionaryModule);
55
- }
56
- if (!Object.keys(dictionary).length)
57
- throw new Error(`Dictionary filepath provided: "${options.dictionary}", but no entries found.`);
58
- // ----- CREATE PARTIAL UPDATES ----- //
59
- let updates = [];
60
- for (const id of Object.keys(dictionary)) {
61
- let { entry, metadata: props, // context, etc.
62
- } = (0, internal_1.getEntryAndMetadata)(dictionary[id]);
63
- const source = (0, generaltranslation_1.splitStringToContent)(entry);
64
- const context = props === null || props === void 0 ? void 0 : props.context;
65
- const metadata = Object.assign(Object.assign({ id }, (context && { context })), {
66
- // This hash isn't actually used by the GT API, just for consistency sake
67
- hash: (0, id_1.hashJsxChildren)(Object.assign(Object.assign({ source }, (context && { context })), (id && { id }))) });
68
- updates.push({
69
- type: 'JSX',
70
- source,
71
- metadata,
72
- });
73
- }
74
- return updates;
75
- });
76
- }
@@ -1,5 +0,0 @@
1
- import { Options, Updates } from '../../types';
2
- export default function createInlineUpdates(options: Options, pkg: 'gt-react' | 'gt-next'): Promise<{
3
- updates: Updates;
4
- errors: string[];
5
- }>;
@@ -1,141 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.default = createInlineUpdates;
16
- const fs_1 = __importDefault(require("fs"));
17
- const path_1 = __importDefault(require("path"));
18
- const parser_1 = require("@babel/parser");
19
- const traverse_1 = __importDefault(require("@babel/traverse"));
20
- const id_1 = require("generaltranslation/id");
21
- const parseJsx_1 = require("../jsx/utils/parseJsx");
22
- const parseStringFunction_1 = require("../jsx/utils/parseStringFunction");
23
- const parseAst_1 = require("../jsx/utils/parseAst");
24
- function createInlineUpdates(options, pkg) {
25
- return __awaiter(this, void 0, void 0, function* () {
26
- const updates = [];
27
- const errors = [];
28
- // Use the provided app directory or default to the current directory
29
- const srcDirectory = options.src || ['./'];
30
- // Define the file extensions to look for
31
- const extensions = ['.js', '.jsx', '.tsx'];
32
- /**
33
- * Recursively scan the directory and collect all files with the specified extensions,
34
- * excluding files or directories that start with a dot (.)
35
- * @param dir - The directory to scan
36
- * @returns An array of file paths
37
- */
38
- function getFiles(dir) {
39
- let files = [];
40
- const items = fs_1.default.readdirSync(dir);
41
- for (const item of items) {
42
- // Skip hidden files and directories
43
- if (item.startsWith('.'))
44
- continue;
45
- const fullPath = path_1.default.join(dir, item);
46
- const stat = fs_1.default.statSync(fullPath);
47
- if (stat.isDirectory()) {
48
- // Recursively scan subdirectories
49
- files = files.concat(getFiles(fullPath));
50
- }
51
- else if (extensions.includes(path_1.default.extname(item))) {
52
- // Add files with the specified extensions
53
- files.push(fullPath);
54
- }
55
- }
56
- return files;
57
- }
58
- const files = srcDirectory.flatMap((dir) => getFiles(dir));
59
- for (const file of files) {
60
- const code = fs_1.default.readFileSync(file, 'utf8');
61
- let ast;
62
- try {
63
- ast = (0, parser_1.parse)(code, {
64
- sourceType: 'module',
65
- plugins: ['jsx', 'typescript'],
66
- });
67
- }
68
- catch (error) {
69
- console.error(`Error parsing file ${file}:`, error);
70
- continue;
71
- }
72
- const translationFuncs = [
73
- 'useGT',
74
- 'getGT',
75
- 'T',
76
- 'Var',
77
- 'DateTime',
78
- 'Currency',
79
- 'Num',
80
- 'Branch',
81
- 'Plural',
82
- ];
83
- const importAliases = {};
84
- // handle imports & alias & handle string functions
85
- (0, traverse_1.default)(ast, {
86
- ImportDeclaration(path) {
87
- if (path.node.source.value.startsWith(pkg)) {
88
- const importName = (0, parseAst_1.extractImportName)(path.node, pkg, translationFuncs);
89
- for (const name of importName) {
90
- if (name.original === 'useGT' || name.original === 'getGT') {
91
- (0, parseStringFunction_1.parseStrings)(name.local, path, updates, errors, file);
92
- }
93
- else {
94
- importAliases[name.local] = name.original;
95
- }
96
- }
97
- }
98
- },
99
- VariableDeclarator(path) {
100
- var _a;
101
- // Check if the init is a require call
102
- if (((_a = path.node.init) === null || _a === void 0 ? void 0 : _a.type) === 'CallExpression' &&
103
- path.node.init.callee.type === 'Identifier' &&
104
- path.node.init.callee.name === 'require') {
105
- // Check if it's requiring our package
106
- const args = path.node.init.arguments;
107
- if (args.length === 1 &&
108
- args[0].type === 'StringLiteral' &&
109
- args[0].value.startsWith(pkg)) {
110
- const parentPath = path.parentPath;
111
- if (parentPath.isVariableDeclaration()) {
112
- const importName = (0, parseAst_1.extractImportName)(parentPath.node, pkg, translationFuncs);
113
- for (const name of importName) {
114
- if (name.original === 'useGT' || name.original === 'getGT') {
115
- (0, parseStringFunction_1.parseStrings)(name.local, parentPath, updates, errors, file);
116
- }
117
- else {
118
- importAliases[name.local] = name.original;
119
- }
120
- }
121
- }
122
- }
123
- }
124
- },
125
- });
126
- // Parse <T> components
127
- (0, traverse_1.default)(ast, {
128
- JSXElement(path) {
129
- (0, parseJsx_1.parseJSXElement)(importAliases, path.node, updates, errors, file);
130
- },
131
- });
132
- }
133
- // Post-process to add a hash to each update
134
- yield Promise.all(updates.map((update) => __awaiter(this, void 0, void 0, function* () {
135
- const context = update.metadata.context;
136
- const hash = (0, id_1.hashJsxChildren)(Object.assign(Object.assign({ source: update.source }, (context && { context })), (update.metadata.id && { id: update.metadata.id })));
137
- update.metadata.hash = hash;
138
- })));
139
- return { updates, errors };
140
- });
141
- }
@@ -1,13 +0,0 @@
1
- import { SupportedFrameworks, WrapOptions } from '../../types';
2
- /**
3
- * Wraps all JSX elements in the src directory with a <T> tag, with unique ids.
4
- * - Ignores pure strings
5
- *
6
- * @param options - The options object
7
- * @returns An object containing the updates and errors
8
- */
9
- export default function scanForContent(options: WrapOptions, pkg: 'gt-next' | 'gt-react', framework: SupportedFrameworks): Promise<{
10
- errors: string[];
11
- filesUpdated: string[];
12
- warnings: string[];
13
- }>;
@@ -1,200 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
- return new (P || (P = Promise))(function (resolve, reject) {
38
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
- step((generator = generator.apply(thisArg, _arguments || [])).next());
42
- });
43
- };
44
- var __importDefault = (this && this.__importDefault) || function (mod) {
45
- return (mod && mod.__esModule) ? mod : { "default": mod };
46
- };
47
- Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.default = scanForContent;
49
- const fs_1 = __importDefault(require("fs"));
50
- const path_1 = __importDefault(require("path"));
51
- const t = __importStar(require("@babel/types"));
52
- const parser_1 = require("@babel/parser");
53
- const traverse_1 = __importDefault(require("@babel/traverse"));
54
- const generator_1 = __importDefault(require("@babel/generator"));
55
- const findJsxFilepath_1 = require("../../fs/findJsxFilepath");
56
- const evaluateJsx_1 = require("../jsx/evaluateJsx");
57
- const wrapJsx_1 = require("../jsx/wrapJsx");
58
- const findFilepath_1 = require("../../fs/findFilepath");
59
- const parseAst_1 = require("../jsx/utils/parseAst");
60
- const IMPORT_MAP = {
61
- T: { name: 'T', source: 'gt-react' },
62
- Var: { name: 'Var', source: 'gt-react' },
63
- GTT: { name: 'T', source: 'gt-react' },
64
- GTVar: { name: 'Var', source: 'gt-react' },
65
- GTProvider: { name: 'GTProvider', source: 'gt-react' },
66
- // getLocale: { name: 'getLocale', source: 'gt-react/server' },
67
- };
68
- /**
69
- * Wraps all JSX elements in the src directory with a <T> tag, with unique ids.
70
- * - Ignores pure strings
71
- *
72
- * @param options - The options object
73
- * @returns An object containing the updates and errors
74
- */
75
- function scanForContent(options, pkg, framework) {
76
- return __awaiter(this, void 0, void 0, function* () {
77
- const errors = [];
78
- const warnings = [];
79
- const srcDirectory = options.src || ['./'];
80
- const files = srcDirectory.flatMap((dir) => (0, findJsxFilepath_1.getFiles)(dir));
81
- const filesUpdated = [];
82
- for (const file of files) {
83
- const baseFileName = path_1.default.basename(file);
84
- const configPath = path_1.default.relative(path_1.default.dirname(file), path_1.default.resolve(process.cwd(), options.config));
85
- // Ensure the path starts with ./ or ../
86
- const normalizedConfigPath = configPath.startsWith('.')
87
- ? configPath
88
- : './' + configPath;
89
- const code = fs_1.default.readFileSync(file, 'utf8');
90
- // Create relative path from src directory and remove extension
91
- const relativePath = (0, findFilepath_1.getRelativePath)(file, srcDirectory[0]);
92
- let ast;
93
- try {
94
- ast = (0, parser_1.parse)(code, {
95
- sourceType: 'module',
96
- plugins: ['jsx', 'typescript'],
97
- tokens: true,
98
- createParenthesizedExpressions: true,
99
- });
100
- }
101
- catch (error) {
102
- console.error(`Error parsing file ${file}:`, error);
103
- errors.push(`Failed to parse ${file}: ${error}`);
104
- continue;
105
- }
106
- let modified = false;
107
- let usedImports = [];
108
- let { importAlias, initialImports } = (0, parseAst_1.generateImportMap)(ast, pkg);
109
- // If the file already has a T import, skip processing it
110
- if (initialImports.includes(IMPORT_MAP.T.name)) {
111
- continue;
112
- }
113
- let globalId = 0;
114
- (0, traverse_1.default)(ast, {
115
- JSXElement(path) {
116
- var _a;
117
- if (framework === 'next-pages' &&
118
- options.addGTProvider &&
119
- (baseFileName === '_app.tsx' || baseFileName === '_app.jsx')) {
120
- // Check if this is the top-level JSX element in the default export
121
- let isDefaultExport = false;
122
- let currentPath = path;
123
- // Check if GTProvider already exists in the ancestors
124
- let hasGTProvider = false;
125
- while (currentPath.parentPath) {
126
- if (t.isJSXElement(currentPath.node) &&
127
- t.isJSXIdentifier(currentPath.node.openingElement.name) &&
128
- currentPath.node.openingElement.name.name === 'GTProvider') {
129
- hasGTProvider = true;
130
- break;
131
- }
132
- if (t.isExportDefaultDeclaration(currentPath.parentPath.node)) {
133
- isDefaultExport = true;
134
- }
135
- currentPath = currentPath.parentPath;
136
- }
137
- if (isDefaultExport && !hasGTProvider) {
138
- // Wrap the JSX element with GTProvider
139
- const gtProviderJsx = t.jsxElement(t.jsxOpeningElement(t.jsxIdentifier('GTProvider'), [t.jsxSpreadAttribute(t.identifier('gtConfig'))], false), t.jsxClosingElement(t.jsxIdentifier('GTProvider')), [path.node]);
140
- path.replaceWith(gtProviderJsx);
141
- usedImports.push('GTProvider');
142
- usedImports.push({
143
- local: 'gtConfig',
144
- imported: 'default',
145
- source: normalizedConfigPath,
146
- });
147
- modified = true;
148
- path.skip();
149
- return;
150
- }
151
- }
152
- // Check if this JSX element has any JSX element ancestors
153
- let currentPath = path;
154
- if (t.isJSXElement((_a = currentPath.parentPath) === null || _a === void 0 ? void 0 : _a.node)) {
155
- // If we found a JSX parent, skip processing this node
156
- return;
157
- }
158
- // At this point, we're only processing top-level JSX elements
159
- const opts = Object.assign(Object.assign({}, importAlias), { idPrefix: relativePath, idCount: globalId, usedImports, modified: false, createIds: !options.disableIds, warnings,
160
- file });
161
- const wrapped = (0, wrapJsx_1.handleJsxElement)(path.node, opts, evaluateJsx_1.isMeaningful);
162
- path.replaceWith(wrapped.node);
163
- // Update global counters
164
- modified = modified || opts.modified;
165
- globalId = opts.idCount;
166
- },
167
- });
168
- if (!modified)
169
- continue;
170
- let needsImport = usedImports.filter((imp) => typeof imp === 'string'
171
- ? !initialImports.includes(imp)
172
- : !initialImports.includes(imp.local));
173
- if (needsImport.length > 0) {
174
- (0, parseAst_1.createImports)(ast, needsImport, IMPORT_MAP);
175
- }
176
- try {
177
- const output = (0, generator_1.default)(ast, {
178
- retainLines: true,
179
- retainFunctionParens: true,
180
- comments: true,
181
- compact: 'auto',
182
- }, code);
183
- // Post-process the output to fix import spacing
184
- let processedCode = output.code;
185
- if (needsImport.length > 0) {
186
- // Add newline after the comment only
187
- processedCode = processedCode.replace(/((?:import\s*{\s*(?:T|GTT|Var|GTVar|GTProvider|getLocale)(?:\s*,\s*(?:T|GTT|Var|GTVar|GTProvider|getLocale))*\s*}\s*from|const\s*{\s*(?:T|GTT|Var|GTVar|GTProvider|getLocale)(?:\s*,\s*(?:T|GTT|Var|GTVar|GTProvider|getLocale))*\s*}\s*=\s*require)\s*['"]gt-(?:next|react)(?:\/server)?['"];?)/, '\n$1\n');
188
- }
189
- // Write the modified code back to the file
190
- fs_1.default.writeFileSync(file, processedCode);
191
- filesUpdated.push(file);
192
- }
193
- catch (error) {
194
- console.error(`Error writing file ${file}:`, error);
195
- errors.push(`Failed to write ${file}: ${error}`);
196
- }
197
- }
198
- return { errors, filesUpdated, warnings };
199
- });
200
- }