gtx-cli 2.5.7 → 2.5.9

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 (81) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/api/downloadFileBatch.js +5 -5
  3. package/dist/api/saveLocalEdits.js +4 -3
  4. package/dist/api/uploadFiles.d.ts +1 -1
  5. package/dist/api/uploadFiles.js +5 -4
  6. package/dist/cli/base.d.ts +2 -1
  7. package/dist/cli/base.js +36 -30
  8. package/dist/cli/commands/setupProject.d.ts +7 -0
  9. package/dist/cli/commands/setupProject.js +50 -0
  10. package/dist/cli/commands/stage.d.ts +0 -2
  11. package/dist/cli/commands/stage.js +13 -61
  12. package/dist/cli/commands/translate.js +3 -5
  13. package/dist/cli/flags.js +2 -3
  14. package/dist/cli/next.js +1 -0
  15. package/dist/cli/react.d.ts +1 -0
  16. package/dist/cli/react.js +26 -15
  17. package/dist/config/generateSettings.js +2 -2
  18. package/dist/config/validateSettings.d.ts +1 -1
  19. package/dist/config/validateSettings.js +4 -4
  20. package/dist/console/logger.d.ts +35 -0
  21. package/dist/console/logger.js +270 -0
  22. package/dist/console/logging.d.ts +6 -11
  23. package/dist/console/logging.js +40 -55
  24. package/dist/formats/files/collectFiles.d.ts +6 -0
  25. package/dist/formats/files/collectFiles.js +49 -0
  26. package/dist/formats/files/fileMapping.js +1 -1
  27. package/dist/formats/files/save.js +2 -2
  28. package/dist/formats/files/translate.js +8 -8
  29. package/dist/formats/files/upload.js +7 -6
  30. package/dist/formats/gt/save.js +4 -3
  31. package/dist/formats/json/flattenJson.js +3 -3
  32. package/dist/formats/json/mergeJson.js +19 -18
  33. package/dist/formats/json/parseJson.js +14 -13
  34. package/dist/formats/json/utils.js +16 -15
  35. package/dist/formats/yaml/mergeYaml.js +6 -5
  36. package/dist/formats/yaml/parseYaml.js +4 -3
  37. package/dist/formats/yaml/utils.js +4 -3
  38. package/dist/fs/clearLocaleDirs.js +6 -6
  39. package/dist/fs/config/downloadedVersions.js +3 -3
  40. package/dist/fs/config/parseFilesConfig.js +2 -2
  41. package/dist/fs/config/setupConfig.js +2 -2
  42. package/dist/fs/config/updateConfig.js +2 -2
  43. package/dist/fs/config/updateVersions.js +3 -3
  44. package/dist/fs/copyFile.js +2 -2
  45. package/dist/fs/createLoadTranslationsFile.d.ts +1 -1
  46. package/dist/fs/createLoadTranslationsFile.js +11 -4
  47. package/dist/fs/determineFramework.js +3 -3
  48. package/dist/fs/findFilepath.js +5 -4
  49. package/dist/hooks/postProcess.js +9 -9
  50. package/dist/next/parse/handleInitGT.js +2 -2
  51. package/dist/react/parse/addVitePlugin/index.js +4 -3
  52. package/dist/react/parse/addVitePlugin/installCompiler.js +2 -2
  53. package/dist/react/parse/addVitePlugin/updateViteConfig.js +9 -12
  54. package/dist/react/parse/createDictionaryUpdates.js +4 -3
  55. package/dist/react/parse/createInlineUpdates.js +2 -2
  56. package/dist/setup/wizard.js +17 -16
  57. package/dist/translation/parse.js +4 -3
  58. package/dist/translation/stage.js +4 -4
  59. package/dist/translation/validate.js +6 -6
  60. package/dist/types/index.d.ts +1 -0
  61. package/dist/utils/addExplicitAnchorIds.js +2 -2
  62. package/dist/utils/constants.d.ts +2 -0
  63. package/dist/utils/constants.js +3 -0
  64. package/dist/utils/credentials.js +4 -3
  65. package/dist/utils/installPackage.js +11 -11
  66. package/dist/utils/packageJson.js +4 -3
  67. package/dist/workflow/BranchStep.js +5 -4
  68. package/dist/workflow/DownloadStep.js +5 -5
  69. package/dist/workflow/EnqueueStep.js +2 -2
  70. package/dist/workflow/PollJobsStep.js +4 -4
  71. package/dist/workflow/SetupStep.d.ts +1 -1
  72. package/dist/workflow/SetupStep.js +4 -3
  73. package/dist/workflow/UploadStep.js +3 -3
  74. package/dist/workflow/UserEditDiffsStep.js +2 -2
  75. package/dist/workflow/download.js +4 -3
  76. package/dist/workflow/setupProject.d.ts +13 -0
  77. package/dist/workflow/setupProject.js +48 -0
  78. package/dist/workflow/stage.js +4 -21
  79. package/package.json +3 -3
  80. package/dist/utils/SpinnerManager.d.ts +0 -30
  81. package/dist/utils/SpinnerManager.js +0 -73
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.5.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#823](https://github.com/generaltranslation/gt/pull/823) [`afbd29a`](https://github.com/generaltranslation/gt/commit/afbd29a34b051c76fce387269c4eb4a2e00a5831) Thanks [@brian-lou](https://github.com/brian-lou)! - Deprecate old 'setup' command -> Use 'init' instead. New 'setup' command runs project setup
8
+
9
+ - Updated dependencies [[`afbd29a`](https://github.com/generaltranslation/gt/commit/afbd29a34b051c76fce387269c4eb4a2e00a5831)]:
10
+ - generaltranslation@8.0.3
11
+
12
+ ## 2.5.8
13
+
14
+ ### Patch Changes
15
+
16
+ - [#821](https://github.com/generaltranslation/gt/pull/821) [`321854a`](https://github.com/generaltranslation/gt/commit/321854ad881ca07b6a0207b3b0cbc004c6c0f5a4) Thanks [@brian-lou](https://github.com/brian-lou)! - Refactor CLI Logging behavior
17
+
3
18
  ## 2.5.7
4
19
 
5
20
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
- import { logError, logWarning } from '../console/logging.js';
3
+ import { logger } from '../console/logger.js';
4
4
  import { gt } from '../utils/gt.js';
5
5
  import { validateJsonSchema } from '../formats/json/utils.js';
6
6
  import { validateYamlSchema } from '../formats/yaml/utils.js';
@@ -55,7 +55,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
55
55
  const outputPath = outputPathMap.get(fileKey);
56
56
  const fileProperties = fileTracker.completed.get(fileKey);
57
57
  if (!outputPath || !fileProperties) {
58
- logWarning(`No input/output path found for file: ${fileKey}`);
58
+ logger.warn(`No input/output path found for file: ${fileKey}`);
59
59
  result.failed.push(requestedFile);
60
60
  continue;
61
61
  }
@@ -110,7 +110,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
110
110
  data = JSON.stringify(sortedJsonData, null, 2); // format the data
111
111
  }
112
112
  catch (error) {
113
- logWarning(`Failed to sort GTJson file: ${file.id}: ` + error);
113
+ logger.warn(`Failed to sort GTJson file: ${file.id}: ` + error);
114
114
  }
115
115
  }
116
116
  // Write the file to disk
@@ -132,7 +132,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
132
132
  }
133
133
  }
134
134
  catch (error) {
135
- logError(`Error saving file ${fileKey}: ` + error);
135
+ logger.error(`Error saving file ${fileKey}: ` + error);
136
136
  result.failed.push(requestedFile);
137
137
  }
138
138
  }
@@ -151,7 +151,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
151
151
  return result;
152
152
  }
153
153
  catch (error) {
154
- logError(`An unexpected error occurred while downloading files: ` + error);
154
+ logger.error(`An unexpected error occurred while downloading files: ` + error);
155
155
  }
156
156
  // Mark all files as failed if we get here
157
157
  result.failed = [...requestedFileMap.values()];
@@ -2,7 +2,8 @@ import { aggregateFiles } from '../formats/files/translate.js';
2
2
  import { collectAndSendUserEditDiffs } from './collectUserEditDiffs.js';
3
3
  import { gt } from '../utils/gt.js';
4
4
  import { BranchStep } from '../workflow/BranchStep.js';
5
- import { createSpinner, logErrorAndExit } from '../console/logging.js';
5
+ import { logErrorAndExit } from '../console/logging.js';
6
+ import { logger } from '../console/logger.js';
6
7
  import chalk from 'chalk';
7
8
  /**
8
9
  * Uploads current source files to obtain file references, then collects and sends
@@ -21,7 +22,7 @@ export async function saveLocalEdits(settings) {
21
22
  const branchResult = await branchStep.run();
22
23
  await branchStep.wait();
23
24
  if (!branchResult) {
24
- logErrorAndExit('Failed to resolve git branch information.');
25
+ return logErrorAndExit('Failed to resolve git branch information.');
25
26
  }
26
27
  const uploads = files.map((file) => ({
27
28
  fileName: file.fileName,
@@ -30,7 +31,7 @@ export async function saveLocalEdits(settings) {
30
31
  fileId: file.fileId,
31
32
  versionId: file.versionId,
32
33
  }));
33
- const spinner = createSpinner('dots');
34
+ const spinner = logger.createSpinner('dots');
34
35
  spinner.start('Saving local edits...');
35
36
  await collectAndSendUserEditDiffs(uploads, settings);
36
37
  spinner.stop(chalk.green('Local edits saved successfully'));
@@ -24,4 +24,4 @@ export type UploadData = {
24
24
  export declare function uploadFiles(files: {
25
25
  source: FileUpload;
26
26
  translations: FileUpload[];
27
- }[], options: Settings): Promise<void>;
27
+ }[], options: Settings): Promise<undefined>;
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
- import { createSpinner, exit, logMessage } from '../console/logging.js';
2
+ import { logger } from '../console/logger.js';
3
+ import { exitSync } from '../console/logging.js';
3
4
  import { gt } from '../utils/gt.js';
4
5
  /**
5
6
  * Uploads multiple files to the API
@@ -8,14 +9,14 @@ import { gt } from '../utils/gt.js';
8
9
  * @returns The uploaded content or version ID
9
10
  */
10
11
  export async function uploadFiles(files, options) {
11
- logMessage(chalk.cyan('Files to upload:') +
12
+ logger.message(chalk.cyan('Files to upload:') +
12
13
  '\n' +
13
14
  files
14
15
  .map((file) => ` - ${chalk.bold(file.source.fileName)} -> ${file.translations
15
16
  .map((t) => t.locale)
16
17
  .join(', ')}`)
17
18
  .join('\n'));
18
- const spinner = createSpinner('dots');
19
+ const spinner = logger.createSpinner('dots');
19
20
  spinner.start(`Uploading ${files.length} file${files.length !== 1 ? 's' : ''} to General Translation...`);
20
21
  try {
21
22
  // Upload sources
@@ -35,6 +36,6 @@ export async function uploadFiles(files, options) {
35
36
  }
36
37
  catch {
37
38
  spinner.stop(chalk.red('An unexpected error occurred while uploading files'));
38
- exit(1);
39
+ return exitSync(1);
39
40
  }
40
41
  }
@@ -16,16 +16,17 @@ export declare class BaseCLI {
16
16
  constructor(program: Command, library: SupportedLibraries, additionalModules?: SupportedLibraries[]);
17
17
  init(): void;
18
18
  execute(): void;
19
+ protected setupSetupProjectCommand(): void;
19
20
  protected setupStageCommand(): void;
20
21
  protected setupTranslateCommand(): void;
21
22
  protected setupSendDiffsCommand(): void;
23
+ protected handleSetupProject(initOptions: TranslateFlags): Promise<void>;
22
24
  protected handleStage(initOptions: TranslateFlags): Promise<void>;
23
25
  protected handleTranslate(initOptions: TranslateFlags): Promise<void>;
24
26
  protected setupUploadCommand(): void;
25
27
  protected setupLoginCommand(): void;
26
28
  protected setupInitCommand(): void;
27
29
  protected setupConfigureCommand(): void;
28
- protected setupSetupCommand(): void;
29
30
  protected handleUploadCommand(settings: Settings & UploadOptions): Promise<void>;
30
31
  protected handleSetupReactCommand(options: SetupOptions): Promise<void>;
31
32
  protected handleInitCommand(ranReactSetup: boolean): Promise<void>;
package/dist/cli/base.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createOrUpdateConfig } from '../fs/config/setupConfig.js';
2
2
  import findFilepath from '../fs/findFilepath.js';
3
- import { displayHeader, promptText, logErrorAndExit, endCommand, promptConfirm, promptMultiSelect, logSuccess, logInfo, startCommand, createSpinner, logMessage, } from '../console/logging.js';
3
+ import { displayHeader, promptText, logErrorAndExit, promptConfirm, promptMultiSelect, } from '../console/logging.js';
4
+ import { logger } from '../console/logger.js';
4
5
  import path from 'node:path';
5
6
  import fs from 'node:fs';
6
7
  import { generateSettings } from '../config/generateSettings.js';
@@ -16,6 +17,7 @@ import { areCredentialsSet } from '../utils/credentials.js';
16
17
  import { upload } from '../formats/files/upload.js';
17
18
  import { attachTranslateFlags } from './flags.js';
18
19
  import { handleStage } from './commands/stage.js';
20
+ import { handleSetupProject } from './commands/setupProject.js';
19
21
  import { handleDownload, handleTranslate, postProcessTranslations, } from './commands/translate.js';
20
22
  import { getDownloaded, clearDownloaded } from '../state/recentDownloads.js';
21
23
  import updateConfig from '../fs/config/updateConfig.js';
@@ -33,13 +35,14 @@ export class BaseCLI {
33
35
  this.additionalModules = additionalModules || [];
34
36
  this.setupInitCommand();
35
37
  this.setupConfigureCommand();
36
- this.setupSetupCommand();
37
38
  this.setupUploadCommand();
38
39
  this.setupLoginCommand();
39
40
  this.setupSendDiffsCommand();
40
41
  }
41
42
  // Init is never called in a child class
42
43
  init() {
44
+ this.setupSetupProjectCommand();
45
+ this.setupStageCommand();
43
46
  this.setupTranslateCommand();
44
47
  }
45
48
  // Execute is called by the main program
@@ -49,13 +52,22 @@ export class BaseCLI {
49
52
  process.argv.push('init');
50
53
  }
51
54
  }
55
+ setupSetupProjectCommand() {
56
+ attachTranslateFlags(this.program
57
+ .command('setup')
58
+ .description('Upload source files and setup the project for translation')).action(async (initOptions) => {
59
+ displayHeader('Uploading source files and setting up project...');
60
+ await this.handleSetupProject(initOptions);
61
+ logger.endCommand('Done!');
62
+ });
63
+ }
52
64
  setupStageCommand() {
53
65
  attachTranslateFlags(this.program
54
66
  .command('stage')
55
67
  .description('Submits the project to the General Translation API for translation. Translations created using this command will require human approval.')).action(async (initOptions) => {
56
68
  displayHeader('Staging project for translation with approval required...');
57
69
  await this.handleStage(initOptions);
58
- endCommand('Done!');
70
+ logger.endCommand('Done!');
59
71
  });
60
72
  }
61
73
  setupTranslateCommand() {
@@ -64,7 +76,7 @@ export class BaseCLI {
64
76
  .description('Translate your project using General Translation')).action(async (initOptions) => {
65
77
  displayHeader('Starting translation...');
66
78
  await this.handleTranslate(initOptions);
67
- endCommand('Done!');
79
+ logger.endCommand('Done!');
68
80
  });
69
81
  }
70
82
  setupSendDiffsCommand() {
@@ -76,9 +88,15 @@ export class BaseCLI {
76
88
  const config = findFilepath(['gt.config.json']);
77
89
  const settings = await generateSettings({ config });
78
90
  await saveLocalEdits(settings);
79
- endCommand('Saved local edits');
91
+ logger.endCommand('Saved local edits');
80
92
  });
81
93
  }
94
+ async handleSetupProject(initOptions) {
95
+ const settings = await generateSettings(initOptions);
96
+ // Preprocess shared static assets if configured (move + rewrite sources)
97
+ await processSharedStaticAssets(settings);
98
+ await handleSetupProject(initOptions, settings, this.library);
99
+ }
82
100
  async handleStage(initOptions) {
83
101
  const settings = await generateSettings(initOptions);
84
102
  // Preprocess shared static assets if configured (move + rewrite sources)
@@ -126,7 +144,7 @@ export class BaseCLI {
126
144
  const settings = await generateSettings(initOptions);
127
145
  const options = { ...initOptions, ...settings };
128
146
  await this.handleUploadCommand(options);
129
- endCommand('Done!');
147
+ logger.endCommand('Done!');
130
148
  });
131
149
  }
132
150
  setupLoginCommand() {
@@ -159,7 +177,7 @@ export class BaseCLI {
159
177
  }
160
178
  }
161
179
  await this.handleLoginCommand(options);
162
- endCommand(`Done! A ${options.keyType} key has been generated and saved to your .env.local file.`);
180
+ logger.endCommand(`Done! A ${options.keyType} key has been generated and saved to your .env.local file.`);
163
181
  });
164
182
  }
165
183
  setupInitCommand() {
@@ -179,20 +197,20 @@ export class BaseCLI {
179
197
  defaultValue: true,
180
198
  });
181
199
  if (wrap) {
182
- logInfo(`${chalk.yellow('[EXPERIMENTAL]')} Running React setup wizard...`);
200
+ logger.info(`${chalk.yellow('[EXPERIMENTAL]')} Running React setup wizard...`);
183
201
  await this.handleSetupReactCommand(options);
184
- endCommand(`Done! Since this wizard is experimental, please review the changes and make modifications as needed.
202
+ logger.endCommand(`Done! Since this wizard is experimental, please review the changes and make modifications as needed.
185
203
  Certain aspects of your app may still need manual setup.
186
204
  See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`);
187
205
  ranReactSetup = true;
188
206
  }
189
207
  }
190
208
  if (ranReactSetup) {
191
- startCommand('Setting up project config...');
209
+ logger.startCommand('Setting up project config...');
192
210
  }
193
211
  // Configure gt.config.json
194
212
  await this.handleInitCommand(ranReactSetup);
195
- endCommand('Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs');
213
+ logger.endCommand('Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs');
196
214
  });
197
215
  }
198
216
  setupConfigureCommand() {
@@ -201,22 +219,10 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
201
219
  .description('Configure your project for General Translation. This will create a gt.config.json file in your codebase.')
202
220
  .action(async () => {
203
221
  displayHeader('Configuring project...');
204
- logInfo('Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.');
222
+ logger.info('Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.');
205
223
  // Configure gt.config.json
206
224
  await this.handleInitCommand(false);
207
- endCommand('Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard');
208
- });
209
- }
210
- setupSetupCommand() {
211
- this.program
212
- .command('setup')
213
- .description('Run the setup to configure your Next.js or React project for General Translation')
214
- .option('--src <paths...>', "Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'")
215
- .option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
216
- .action(async (options) => {
217
- displayHeader('Running React setup wizard...');
218
- await this.handleSetupReactCommand(options);
219
- endCommand("Done! Take advantage of all of General Translation's features by signing up for a free account! https://generaltranslation.com/signup");
225
+ logger.endCommand('Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard');
220
226
  });
221
227
  }
222
228
  async handleUploadCommand(settings) {
@@ -264,7 +270,7 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
264
270
  message: `Auto-detected that you're using gt-next or gt-react. Would you like to use the General Translation CDN to store your translations?\nSee ${isUsingGTNext
265
271
  ? 'https://generaltranslation.com/en/docs/next/guides/local-tx'
266
272
  : 'https://generaltranslation.com/en/docs/react/guides/local-tx'} for more information.\nIf you answer no, we'll configure the CLI tool to download completed translations.`,
267
- defaultValue: true,
273
+ defaultValue: false,
268
274
  })
269
275
  : false;
270
276
  // Ask where the translations are stored
@@ -278,8 +284,8 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
278
284
  const finalTranslationsDir = translationsDir?.trim() || './public/_gt';
279
285
  if (isUsingGT && !usingCDN) {
280
286
  // Create loadTranslations.js file for local translations
281
- await createLoadTranslationsFile(process.cwd(), finalTranslationsDir);
282
- logMessage(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.
287
+ await createLoadTranslationsFile(process.cwd(), finalTranslationsDir, locales);
288
+ logger.message(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.
283
289
  Make sure to add this function to your app configuration.
284
290
  See https://generaltranslation.com/en/docs/next/guides/local-tx`);
285
291
  }
@@ -325,14 +331,14 @@ See https://generaltranslation.com/en/docs/next/guides/local-tx`);
325
331
  files: Object.keys(files).length > 0 ? files : undefined,
326
332
  publish: isUsingGT && usingCDN,
327
333
  });
328
- logSuccess(`Feel free to edit ${chalk.cyan(configFilepath)} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
334
+ logger.success(`Feel free to edit ${chalk.cyan(configFilepath)} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
329
335
  // Install gtx-cli if not installed
330
336
  const isCLIInstalled = packageJson
331
337
  ? isPackageInstalled('gtx-cli', packageJson, true, true)
332
338
  : true; // if no package.json, we can't install it
333
339
  if (!isCLIInstalled) {
334
340
  const packageManager = await getPackageManager();
335
- const spinner = createSpinner();
341
+ const spinner = logger.createSpinner();
336
342
  spinner.start(`Installing gtx-cli as a dev dependency with ${packageManager.name}...`);
337
343
  await installPackage('gtx-cli', packageManager, true);
338
344
  spinner.stop(chalk.green('Installed gtx-cli.'));
@@ -0,0 +1,7 @@
1
+ import { Settings, SupportedLibraries, TranslateFlags } from '../../types/index.js';
2
+ import { FileTranslationData } from '../../workflow/download.js';
3
+ import { BranchData } from '../../types/branch.js';
4
+ export declare function handleSetupProject(options: TranslateFlags, settings: Settings, library: SupportedLibraries): Promise<{
5
+ fileVersionData: FileTranslationData | undefined;
6
+ branchData: BranchData | undefined;
7
+ } | null>;
@@ -0,0 +1,50 @@
1
+ import { logger } from '../../console/logger.js';
2
+ import { logCollectedFiles, logErrorAndExit } from '../../console/logging.js';
3
+ import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, } from '../../console/index.js';
4
+ import { collectFiles } from '../../formats/files/collectFiles.js';
5
+ import { setupProject } from '../../workflow/setupProject.js';
6
+ export async function handleSetupProject(options, settings, library) {
7
+ // Validate required settings are present if not in dry run
8
+ if (!options.dryRun) {
9
+ if (!settings.locales) {
10
+ return logErrorAndExit(noLocalesError);
11
+ }
12
+ if (!settings.defaultLocale) {
13
+ return logErrorAndExit(noDefaultLocaleError);
14
+ }
15
+ if (!settings.apiKey) {
16
+ return logErrorAndExit(noApiKeyError);
17
+ }
18
+ if (settings.apiKey.startsWith('gtx-dev-')) {
19
+ return logErrorAndExit(devApiKeyError);
20
+ }
21
+ if (!settings.projectId) {
22
+ return logErrorAndExit(noProjectIdError);
23
+ }
24
+ }
25
+ const { files: allFiles, reactComponents } = await collectFiles(options, settings, library);
26
+ // Dry run
27
+ if (options.dryRun) {
28
+ logger.success(`Dry run: No files were uploaded to General Translation.`);
29
+ logCollectedFiles(allFiles, reactComponents);
30
+ return null;
31
+ }
32
+ // Upload files and run setup step
33
+ let fileVersionData;
34
+ let branchData;
35
+ if (allFiles.length > 0) {
36
+ const { branchData: branchDataResult } = await setupProject(allFiles, options, settings);
37
+ branchData = branchDataResult;
38
+ fileVersionData = Object.fromEntries(allFiles.map((file) => [
39
+ file.fileId,
40
+ {
41
+ fileName: file.fileName,
42
+ versionId: file.versionId,
43
+ },
44
+ ]));
45
+ }
46
+ return {
47
+ fileVersionData,
48
+ branchData,
49
+ };
50
+ }
@@ -2,8 +2,6 @@ import { Settings, SupportedLibraries, TranslateFlags } from '../../types/index.
2
2
  import type { EnqueueFilesResult } from 'generaltranslation/types';
3
3
  import { FileTranslationData } from '../../workflow/download.js';
4
4
  import { BranchData } from '../../types/branch.js';
5
- export declare const TEMPLATE_FILE_NAME = "__INTERNAL_GT_TEMPLATE_NAME__";
6
- export declare const TEMPLATE_FILE_ID: string;
7
5
  export declare function handleStage(options: TranslateFlags, settings: Settings, library: SupportedLibraries, stage: boolean): Promise<{
8
6
  fileVersionData: FileTranslationData | undefined;
9
7
  jobData: EnqueueFilesResult | undefined;
@@ -1,83 +1,35 @@
1
- import { logErrorAndExit, logSuccess } from '../../console/logging.js';
2
- import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, invalidConfigurationError, } from '../../console/index.js';
3
- import { aggregateFiles } from '../../formats/files/translate.js';
4
- import { aggregateReactTranslations } from '../../translation/stage.js';
1
+ import { logger } from '../../console/logger.js';
2
+ import { logCollectedFiles, logErrorAndExit } from '../../console/logging.js';
3
+ import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, } from '../../console/index.js';
5
4
  import { stageFiles } from '../../workflow/stage.js';
6
5
  import { updateVersions } from '../../fs/config/updateVersions.js';
7
6
  import updateConfig from '../../fs/config/updateConfig.js';
8
- import { hashStringSync } from '../../utils/hash.js';
9
- export const TEMPLATE_FILE_NAME = '__INTERNAL_GT_TEMPLATE_NAME__';
10
- export const TEMPLATE_FILE_ID = hashStringSync(TEMPLATE_FILE_NAME);
7
+ import { TEMPLATE_FILE_ID } from '../../utils/constants.js';
8
+ import { collectFiles } from '../../formats/files/collectFiles.js';
11
9
  export async function handleStage(options, settings, library, stage) {
12
10
  // Validate required settings are present if not in dry run
13
11
  if (!options.dryRun) {
14
12
  if (!settings.locales) {
15
- logErrorAndExit(noLocalesError);
13
+ return logErrorAndExit(noLocalesError);
16
14
  }
17
15
  if (!settings.defaultLocale) {
18
- logErrorAndExit(noDefaultLocaleError);
16
+ return logErrorAndExit(noDefaultLocaleError);
19
17
  }
20
18
  if (!settings.apiKey) {
21
- logErrorAndExit(noApiKeyError);
19
+ return logErrorAndExit(noApiKeyError);
22
20
  }
23
21
  if (settings.apiKey.startsWith('gtx-dev-')) {
24
- logErrorAndExit(devApiKeyError);
22
+ return logErrorAndExit(devApiKeyError);
25
23
  }
26
24
  if (!settings.projectId) {
27
- logErrorAndExit(noProjectIdError);
28
- }
29
- }
30
- // Aggregate files
31
- const allFiles = await aggregateFiles(settings);
32
- // Parse for React components
33
- let reactComponents = 0;
34
- if (library === 'gt-react' || library === 'gt-next') {
35
- const updates = await aggregateReactTranslations(options, settings, library);
36
- if (updates.length > 0) {
37
- if (!options.dryRun &&
38
- !settings.publish &&
39
- !settings.files?.placeholderPaths.gt) {
40
- logErrorAndExit(invalidConfigurationError);
41
- }
42
- reactComponents = updates.length;
43
- // Convert updates to a file object
44
- const fileData = {};
45
- const fileMetadata = {};
46
- // Convert updates to the proper data format
47
- for (const update of updates) {
48
- const { source, metadata, dataFormat } = update;
49
- metadata.dataFormat = dataFormat; // add the data format to the metadata
50
- const { hash, id } = metadata;
51
- if (id) {
52
- fileData[id] = source;
53
- fileMetadata[id] = metadata;
54
- }
55
- else {
56
- fileData[hash] = source;
57
- fileMetadata[hash] = metadata;
58
- }
59
- }
60
- allFiles.push({
61
- fileName: TEMPLATE_FILE_NAME,
62
- content: JSON.stringify(fileData),
63
- fileFormat: 'GTJSON',
64
- formatMetadata: fileMetadata,
65
- fileId: TEMPLATE_FILE_ID,
66
- versionId: hashStringSync(JSON.stringify(fileData)),
67
- });
25
+ return logErrorAndExit(noProjectIdError);
68
26
  }
69
27
  }
28
+ const { files: allFiles, reactComponents } = await collectFiles(options, settings, library);
70
29
  // Dry run
71
30
  if (options.dryRun) {
72
- const fileNames = allFiles
73
- .map((file) => {
74
- if (file.fileName === TEMPLATE_FILE_NAME) {
75
- return `- <React Elements> (${reactComponents})`;
76
- }
77
- return `- ${file.fileName}`;
78
- })
79
- .join('\n');
80
- logSuccess(`Dry run: No files were sent to General Translation. Found files:\n${fileNames}`);
31
+ logger.success(`Dry run: No files were sent to General Translation.`);
32
+ logCollectedFiles(allFiles, reactComponents);
81
33
  return null;
82
34
  }
83
35
  // Send translations to General Translation
@@ -1,6 +1,5 @@
1
1
  import { downloadTranslations, } from '../../workflow/download.js';
2
2
  import { createFileMapping } from '../../formats/files/fileMapping.js';
3
- import { logError } from '../../console/logging.js';
4
3
  import { getStagedVersions } from '../../fs/config/updateVersions.js';
5
4
  import copyFile from '../../fs/copyFile.js';
6
5
  import flattenJsonFiles from '../../utils/flattenJsonFiles.js';
@@ -8,6 +7,7 @@ import localizeStaticUrls from '../../utils/localizeStaticUrls.js';
8
7
  import processAnchorIds from '../../utils/processAnchorIds.js';
9
8
  import { noFilesError, noVersionIdError } from '../../console/index.js';
10
9
  import localizeStaticImports from '../../utils/localizeStaticImports.js';
10
+ import { logErrorAndExit } from '../../console/logging.js';
11
11
  // Downloads translations that were completed
12
12
  export async function handleTranslate(options, settings, fileVersionData, jobData, branchData) {
13
13
  if (fileVersionData) {
@@ -20,12 +20,10 @@ export async function handleTranslate(options, settings, fileVersionData, jobDat
20
20
  // Downloads translations that were originally staged
21
21
  export async function handleDownload(options, settings) {
22
22
  if (!settings._versionId) {
23
- logError(noVersionIdError);
24
- process.exit(1);
23
+ logErrorAndExit(noVersionIdError);
25
24
  }
26
25
  if (!settings.files) {
27
- logError(noFilesError);
28
- process.exit(1);
26
+ logErrorAndExit(noFilesError);
29
27
  }
30
28
  // Files
31
29
  const { resolvedPaths, placeholderPaths, transformPaths } = settings.files;
package/dist/cli/flags.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import findFilepath from '../fs/findFilepath.js';
2
- import { logErrorAndExit } from '../console/logging.js';
3
2
  const DEFAULT_TIMEOUT = 600;
4
3
  export function attachTranslateFlags(command) {
5
4
  command
@@ -13,10 +12,10 @@ export function attachTranslateFlags(command) {
13
12
  .option('--timeout <seconds>', 'Translation wait timeout in seconds', (value) => {
14
13
  const parsedValue = parseInt(value, 10);
15
14
  if (isNaN(parsedValue)) {
16
- logErrorAndExit('Not a number.');
15
+ throw new Error('Invalid timeout: not a number.');
17
16
  }
18
17
  if (parsedValue < 0) {
19
- logErrorAndExit('Timeout must be a positive number.');
18
+ throw new Error('Invalid timeout: must be a positive number.');
20
19
  }
21
20
  return parsedValue;
22
21
  }, DEFAULT_TIMEOUT)
package/dist/cli/next.js CHANGED
@@ -6,6 +6,7 @@ export class NextCLI extends ReactCLI {
6
6
  super(command, library, additionalModules);
7
7
  }
8
8
  init() {
9
+ this.setupSetupProjectCommand();
9
10
  this.setupStageCommand();
10
11
  this.setupTranslateCommand();
11
12
  this.setupGenerateSourceCommand();
@@ -8,6 +8,7 @@ export declare class ReactCLI extends BaseCLI {
8
8
  protected wrapContent(options: WrapOptions, framework: SupportedFrameworks, errors: string[], warnings: string[]): Promise<{
9
9
  filesUpdated: string[];
10
10
  }>;
11
+ protected setupSetupProjectCommand(): void;
11
12
  protected setupStageCommand(): void;
12
13
  protected setupTranslateCommand(): void;
13
14
  protected setupValidateCommand(): void;