gt 2.14.31 → 2.14.32

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,14 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.14.32
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1338](https://github.com/generaltranslation/gt/pull/1338) [`66b5df5`](https://github.com/generaltranslation/gt/commit/66b5df57a69d224345ad0a6191437ba8aca3a19d) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Generate explicit relative import paths in `loadTranslations.js` for local
8
+ translation files.
9
+
10
+ - [#1314](https://github.com/generaltranslation/gt/pull/1314) [`a13629f`](https://github.com/generaltranslation/gt/commit/a13629f2c5e5a2fcc22c34704507bcc591174825) Thanks [@bgub](https://github.com/bgub)! - Show a warning download status when completed files are missing from the download response.
11
+
3
12
  ## 2.14.31
4
13
 
5
14
  ### Patch Changes
@@ -142,9 +142,7 @@ export async function generateSettings(flags, cwd = process.cwd(), options) {
142
142
  // Don't default src here — each pipeline (JS/Python) has its own defaults.
143
143
  // Only set src if the user explicitly provided it via flags or config.
144
144
  // Resolve all glob patterns in the files object
145
- const compositePatterns = [
146
- ...Object.entries(mergedOptions.options?.jsonSchema || {}),
147
- ]
145
+ const compositePatterns = Object.entries(mergedOptions.options?.jsonSchema || {})
148
146
  .filter(([, schema]) => schema.composite)
149
147
  .map(([key]) => key);
150
148
  mergedOptions.files = mergedOptions.files
@@ -162,9 +160,9 @@ export async function generateSettings(flags, cwd = process.cwd(), options) {
162
160
  },
163
161
  };
164
162
  mergedOptions.options = {
165
- ...(mergedOptions.options || {}),
163
+ ...mergedOptions.options,
166
164
  mintlify: {
167
- ...(mergedOptions.options?.mintlify || {}),
165
+ ...mergedOptions.options?.mintlify,
168
166
  inferTitleFromFilename: gtConfig.options?.mintlify?.inferTitleFromFilename ||
169
167
  mergedOptions.options?.mintlify?.inferTitleFromFilename,
170
168
  },
@@ -7,6 +7,7 @@ import { TEMPLATE_FILE_NAME } from '../utils/constants.js';
7
7
  * Strip ANSI escape codes from a string (e.g., chalk color codes)
8
8
  */
9
9
  export function stripAnsi(str) {
10
+ // eslint-disable-next-line no-control-regex, no-useless-escape
10
11
  return str.replace(/\x1B\[[0-9;]*m/g, '');
11
12
  }
12
13
  export function logErrorAndExit(message) {
@@ -27,6 +28,7 @@ export function displayHeader(introString) {
27
28
  }
28
29
  }
29
30
  function displayAsciiTitle() {
31
+ // eslint-disable-next-line no-console
30
32
  console.log(chalk.cyan(`\n ,ad8888ba, 888888888888
31
33
  d8"' \`"8b 88
32
34
  d8' 88
@@ -38,6 +40,7 @@ Y8, 88 88
38
40
  }
39
41
  function displayInitializingText() {
40
42
  const version = getCLIVersion();
43
+ // eslint-disable-next-line no-console
41
44
  console.log(`\n${chalk.bold.blue('General Translation, Inc.')}
42
45
  ${chalk.dim('https://generaltranslation.com/docs')}
43
46
  ${chalk.dim(`CLI Version: ${version}\n`)}`);
@@ -147,17 +147,14 @@ export function validateJsonSchema(options, filePath) {
147
147
  if (jsonSchema.include && jsonSchema.composite) {
148
148
  logger.error('include and composite cannot be used together in the same JSON schema');
149
149
  return exitSync(1);
150
- return null;
151
150
  }
152
151
  if (!jsonSchema.include && !jsonSchema.composite) {
153
152
  logger.error('No include or composite property found in JSON schema');
154
153
  return exitSync(1);
155
- return null;
156
154
  }
157
155
  if (jsonSchema.structuralTransform && !jsonSchema.composite) {
158
156
  logger.error('structuralTransform requires composite to be defined in the JSON schema');
159
157
  return exitSync(1);
160
- return null;
161
158
  }
162
159
  return jsonSchema;
163
160
  }
@@ -3,14 +3,27 @@ import path from 'node:path';
3
3
  import { logger } from '../console/logger.js';
4
4
  import chalk from 'chalk';
5
5
  import { DEFAULT_TRANSLATIONS_DIR } from '../utils/constants.js';
6
+ function toRelativeImportPath(relativePath) {
7
+ const normalizedPath = relativePath.split(path.sep).join(path.posix.sep);
8
+ if (!normalizedPath) {
9
+ return './';
10
+ }
11
+ // Dynamic imports must use explicit relative specifiers; values like
12
+ // "src/_gt" are otherwise treated as package names by Vite and Node.
13
+ const hasExplicitRelativePrefix = normalizedPath === '..' ||
14
+ normalizedPath.startsWith('../') ||
15
+ normalizedPath.startsWith('./');
16
+ return hasExplicitRelativePrefix
17
+ ? `${normalizedPath}/`
18
+ : `./${normalizedPath}/`;
19
+ }
6
20
  export async function createLoadTranslationsFile(appDirectory, translationsDir = DEFAULT_TRANSLATIONS_DIR, locales) {
7
21
  const usingSrcDirectory = fs.existsSync(path.join(appDirectory, 'src'));
8
- // Calculate the relative path from the loadTranslations.js location to the translations directory
9
22
  const loadTranslationsDir = usingSrcDirectory
10
23
  ? path.join(appDirectory, 'src')
11
24
  : appDirectory;
12
25
  const relativePath = path.relative(loadTranslationsDir, path.resolve(appDirectory, translationsDir));
13
- const publicPath = relativePath ? `${relativePath}/` : './';
26
+ const publicPath = toRelativeImportPath(relativePath);
14
27
  const filePath = usingSrcDirectory
15
28
  ? path.join(appDirectory, 'src', 'loadTranslations.js')
16
29
  : path.join(appDirectory, 'loadTranslations.js');
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.14.31";
1
+ export declare const PACKAGE_VERSION = "2.14.32";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.14.31';
2
+ export const PACKAGE_VERSION = '2.14.32';
@@ -31,12 +31,10 @@ export function removeNullChildrenFields(tree) {
31
31
  if (child && 'd' in child && child.d != null) {
32
32
  let b;
33
33
  if (child.d && 'b' in child.d && child.d.b != null) {
34
- b = {
35
- ...Object.fromEntries(Object.entries(child.d.b).map(([key, value]) => [
36
- key,
37
- handleChildren(value),
38
- ])),
39
- };
34
+ b = Object.fromEntries(Object.entries(child.d.b).map(([key, value]) => [
35
+ key,
36
+ handleChildren(value),
37
+ ]));
40
38
  }
41
39
  d = {
42
40
  ...(b != null && { b }),
@@ -49,7 +49,7 @@ function unwrapTypeAnnotation(node) {
49
49
  * Collects all resolvable property entries from an ObjectExpression,
50
50
  * including entries from spread sources.
51
51
  */
52
- function collectObjectProperties(objExpr, tPath, file, parsingOptions, warnings, errors = []) {
52
+ function collectObjectProperties(objExpr, tPath, file, parsingOptions, errors = []) {
53
53
  const entries = [];
54
54
  for (const prop of objExpr.properties) {
55
55
  if (t.isObjectProperty(prop)) {
@@ -68,7 +68,7 @@ function collectObjectProperties(objExpr, tPath, file, parsingOptions, warnings,
68
68
  // Handle inline ObjectExpression spread: { ...({ a: 'x' }) }
69
69
  const spreadArg = unwrapTypeAnnotation(prop.argument);
70
70
  if (t.isObjectExpression(spreadArg)) {
71
- entries.push(...collectObjectProperties(spreadArg, tPath, file, parsingOptions, warnings, errors));
71
+ entries.push(...collectObjectProperties(spreadArg, tPath, file, parsingOptions, errors));
72
72
  continue;
73
73
  }
74
74
  if (!t.isIdentifier(prop.argument))
@@ -96,7 +96,7 @@ function collectObjectProperties(objExpr, tPath, file, parsingOptions, warnings,
96
96
  resolvingIdentifiers.delete(spreadInit);
97
97
  continue;
98
98
  }
99
- entries.push(...collectObjectProperties(spreadObj, spreadBinding.path, file, parsingOptions, warnings, errors));
99
+ entries.push(...collectObjectProperties(spreadObj, spreadBinding.path, file, parsingOptions, errors));
100
100
  resolvingIdentifiers.delete(spreadInit);
101
101
  }
102
102
  // Cross-file: ImportSpecifier or ImportDefaultSpecifier
@@ -117,11 +117,11 @@ function collectObjectProperties(objExpr, tPath, file, parsingOptions, warnings,
117
117
  const resolvedFilePath = resolveImportPath(file, importPath, parsingOptions, resolveImportPathCache);
118
118
  if (!resolvedFilePath)
119
119
  continue;
120
- const crossFileObjects = resolveObjectNodesInFile(resolvedFilePath, originalName, parsingOptions, warnings);
120
+ const crossFileObjects = resolveObjectNodesInFile(resolvedFilePath, originalName, parsingOptions);
121
121
  for (const crossObj of crossFileObjects) {
122
122
  const crossEntries = t.isArrayExpression(crossObj.objExpr)
123
- ? collectArrayElements(crossObj.objExpr, crossObj.tPath, crossObj.file, parsingOptions, warnings)
124
- : collectObjectProperties(crossObj.objExpr, crossObj.tPath, crossObj.file, parsingOptions, warnings, errors);
123
+ ? collectArrayElements(crossObj.objExpr, crossObj.tPath, crossObj.file, parsingOptions)
124
+ : collectObjectProperties(crossObj.objExpr, crossObj.tPath, crossObj.file, parsingOptions, errors);
125
125
  entries.push(...crossEntries);
126
126
  }
127
127
  }
@@ -134,7 +134,7 @@ function collectObjectProperties(objExpr, tPath, file, parsingOptions, warnings,
134
134
  * Collects elements from an ArrayExpression as ObjectEntry[] with index as key.
135
135
  * Handles spread elements by resolving the source array.
136
136
  */
137
- function collectArrayElements(arrExpr, tPath, file, parsingOptions, warnings, errors = []) {
137
+ function collectArrayElements(arrExpr, tPath, file, parsingOptions, errors = []) {
138
138
  const entries = [];
139
139
  let index = 0;
140
140
  for (const el of arrExpr.elements) {
@@ -162,7 +162,7 @@ function collectArrayElements(arrExpr, tPath, file, parsingOptions, warnings, er
162
162
  continue;
163
163
  const spreadUnwrapped = unwrapTypeAnnotation(spreadInit);
164
164
  if (t.isArrayExpression(spreadUnwrapped)) {
165
- const spreadEntries = collectArrayElements(spreadUnwrapped, spreadBinding.path, file, parsingOptions, warnings);
165
+ const spreadEntries = collectArrayElements(spreadUnwrapped, spreadBinding.path, file, parsingOptions);
166
166
  for (const e of spreadEntries) {
167
167
  entries.push({ key: String(index++), value: e.value });
168
168
  }
@@ -187,10 +187,10 @@ function collectArrayElements(arrExpr, tPath, file, parsingOptions, warnings, er
187
187
  const resolvedFilePath = resolveImportPath(file, importPath, parsingOptions, resolveImportPathCache);
188
188
  if (!resolvedFilePath)
189
189
  continue;
190
- const crossFileNodes = resolveObjectNodesInFile(resolvedFilePath, originalName, parsingOptions, warnings);
190
+ const crossFileNodes = resolveObjectNodesInFile(resolvedFilePath, originalName, parsingOptions);
191
191
  for (const crossNode of crossFileNodes) {
192
192
  if (t.isArrayExpression(crossNode.objExpr)) {
193
- const spreadEntries = collectArrayElements(crossNode.objExpr, crossNode.tPath, crossNode.file, parsingOptions, warnings);
193
+ const spreadEntries = collectArrayElements(crossNode.objExpr, crossNode.tPath, crossNode.file, parsingOptions);
194
194
  for (const e of spreadEntries) {
195
195
  entries.push({ key: String(index++), value: e.value });
196
196
  }
@@ -275,7 +275,7 @@ function resolveToObjectNodes(node, tPath, file, parsingOptions, warnings, error
275
275
  const resolvedFilePath = resolveImportPath(file, importPath, parsingOptions, resolveImportPathCache);
276
276
  if (!resolvedFilePath)
277
277
  return [];
278
- return resolveObjectNodesInFile(resolvedFilePath, originalName, parsingOptions, warnings);
278
+ return resolveObjectNodesInFile(resolvedFilePath, originalName, parsingOptions);
279
279
  }
280
280
  return [];
281
281
  }
@@ -289,8 +289,8 @@ function resolveToObjectNodes(node, tPath, file, parsingOptions, warnings, error
289
289
  const results = [];
290
290
  for (const parent of parentObjects) {
291
291
  const entries = t.isArrayExpression(parent.objExpr)
292
- ? collectArrayElements(parent.objExpr, parent.tPath, parent.file, parsingOptions, warnings)
293
- : collectObjectProperties(parent.objExpr, parent.tPath, parent.file, parsingOptions, warnings, errors);
292
+ ? collectArrayElements(parent.objExpr, parent.tPath, parent.file, parsingOptions)
293
+ : collectObjectProperties(parent.objExpr, parent.tPath, parent.file, parsingOptions, errors);
294
294
  // Determine if this is a static access (known key)
295
295
  let staticKey = null;
296
296
  if (!node.computed && t.isIdentifier(node.property)) {
@@ -342,7 +342,7 @@ function resolveToObjectNodes(node, tPath, file, parsingOptions, warnings, error
342
342
  * Finds a const VariableDeclarator with ObjectExpression init.
343
343
  * Follows re-export chains.
344
344
  */
345
- function resolveObjectNodesInFile(filePath, name, parsingOptions, warnings) {
345
+ function resolveObjectNodesInFile(filePath, name, parsingOptions) {
346
346
  const cacheKey = `${filePath}::${name}`;
347
347
  if (resolveObjectNodeCache.has(cacheKey)) {
348
348
  return resolveObjectNodeCache.get(cacheKey);
@@ -384,7 +384,7 @@ function resolveObjectNodesInFile(filePath, name, parsingOptions, warnings) {
384
384
  const reexportPath = path.node.source.value;
385
385
  const resolvedPath = resolveImportPath(filePath, reexportPath, parsingOptions, resolveImportPathCache);
386
386
  if (resolvedPath) {
387
- results.push(...resolveObjectNodesInFile(resolvedPath, name, parsingOptions, warnings));
387
+ results.push(...resolveObjectNodesInFile(resolvedPath, name, parsingOptions));
388
388
  }
389
389
  }
390
390
  },
@@ -420,7 +420,7 @@ function resolveObjectNodesInFile(filePath, name, parsingOptions, warnings) {
420
420
  t.isIdentifier(specifier.local)) {
421
421
  originalName = specifier.local.name;
422
422
  }
423
- results.push(...resolveObjectNodesInFile(resolvedPath, originalName, parsingOptions, warnings));
423
+ results.push(...resolveObjectNodesInFile(resolvedPath, originalName, parsingOptions));
424
424
  }
425
425
  }
426
426
  }
@@ -594,8 +594,8 @@ export function parseStringExpression(node, tPath, file, parsingOptions, warning
594
594
  const branches = [];
595
595
  for (const { objExpr, tPath: objPath, file: objFile } of objectNodes) {
596
596
  const entries = t.isArrayExpression(objExpr)
597
- ? collectArrayElements(objExpr, objPath, objFile, parsingOptions, warnings, errors)
598
- : collectObjectProperties(objExpr, objPath, objFile, parsingOptions, warnings, errors);
597
+ ? collectArrayElements(objExpr, objPath, objFile, parsingOptions, errors)
598
+ : collectObjectProperties(objExpr, objPath, objFile, parsingOptions, errors);
599
599
  // Check for static literal subscripts: obj['key'] or obj[0]
600
600
  let staticLiteralKey = null;
601
601
  if (node.computed && t.isStringLiteral(node.property)) {
@@ -15,7 +15,7 @@ export async function retrieveCredentials(settings, keyType) {
15
15
  logger.message(`${chalk.dim(`If the browser window didn't open automatically, please open the following link:`)}\n\n${chalk.cyan(urlToOpen)}`);
16
16
  const spinner = logger.createSpinner('dots');
17
17
  spinner.start('Waiting for response from dashboard...');
18
- const credentials = await new Promise(async (resolve) => {
18
+ const credentials = await new Promise((resolve) => {
19
19
  const interval = setInterval(async () => {
20
20
  // Ping the dashboard to see if the credentials are set
21
21
  try {
@@ -15,15 +15,7 @@ export class DownloadTranslationsStep extends WorkflowStep {
15
15
  async run({ fileTracker, resolveOutputPath, forceDownload, }) {
16
16
  this.spinner = logger.createProgressBar(fileTracker.completed.size);
17
17
  this.spinner.start('Downloading files...');
18
- // Download ready files
19
- const success = await this.downloadFiles(fileTracker, resolveOutputPath, forceDownload);
20
- if (success) {
21
- this.spinner.stop(chalk.green('Downloaded files successfully'));
22
- }
23
- else {
24
- this.spinner.stop(chalk.red('Failed to download files'));
25
- }
26
- return success;
18
+ return this.downloadFiles(fileTracker, resolveOutputPath, forceDownload);
27
19
  }
28
20
  async downloadFiles(fileTracker, resolveOutputPath, forceDownload) {
29
21
  try {
@@ -31,6 +23,7 @@ export class DownloadTranslationsStep extends WorkflowStep {
31
23
  const currentQueryData = Array.from(fileTracker.completed.values());
32
24
  // If no files to download, we're done
33
25
  if (currentQueryData.length === 0) {
26
+ this.spinner?.stop(chalk.green('No files to download'));
34
27
  return true;
35
28
  }
36
29
  // Check for translations
@@ -45,9 +38,11 @@ export class DownloadTranslationsStep extends WorkflowStep {
45
38
  const translatedFiles = responseData.translatedFiles || [];
46
39
  // Filter for ready translations
47
40
  const readyTranslations = translatedFiles.filter((file) => file.completedAt !== null);
41
+ let missingCount = 0;
48
42
  if (readyTranslations.length < currentQueryData.length) {
49
43
  const readyKeys = new Set(readyTranslations.map((t) => `${t.branchId}:${t.fileId}:${t.versionId}:${t.locale}`));
50
44
  const missing = currentQueryData.filter((item) => !readyKeys.has(`${item.branchId}:${item.fileId}:${item.versionId}:${item.locale}`));
45
+ missingCount = missing.length;
51
46
  logger.warn(`Failed to download ${missing.length} file(s):\n${missing.map((f) => `- ${f.fileName} (${f.locale})`).join('\n')}`);
52
47
  for (const f of missing) {
53
48
  recordWarning('failed_download', f.fileName, `Failed to download for locale ${f.locale}`);
@@ -88,6 +83,9 @@ export class DownloadTranslationsStep extends WorkflowStep {
88
83
  }
89
84
  }
90
85
  }
86
+ else if (missingCount > 0) {
87
+ this.spinner?.stop(chalk.yellow('No files downloaded - see warnings above'));
88
+ }
91
89
  else {
92
90
  this.spinner?.stop(chalk.green('No files to download'));
93
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.14.31",
3
+ "version": "2.14.32",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -148,8 +148,6 @@
148
148
  "build:bin:linux-x64": "sh scripts/build-exe.sh linux-x64",
149
149
  "build:bin:linux-arm64": "sh scripts/build-exe.sh linux-arm64",
150
150
  "build:bin:windows-x64": "sh scripts/build-exe.sh windows-x64",
151
- "lint": "eslint \"src/**/*.{js,ts}\" \"./**/__tests__/**/*.{js,ts}\"",
152
- "lint:fix": "eslint \"src/**/*.{js,ts}\" \"./**/__tests__/**/*.{js,ts}\" --fix",
153
151
  "test": "vitest run --config=./vitest.config.ts",
154
152
  "test:watch": "vitest --config=./vitest.config.ts",
155
153
  "release": "pnpm run release:normal && pnpm run release:bin",