gtx-cli 2.5.6 → 2.5.8

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 (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/api/downloadFileBatch.js +6 -6
  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.js +17 -16
  7. package/dist/cli/commands/stage.js +8 -7
  8. package/dist/cli/commands/translate.js +3 -5
  9. package/dist/cli/flags.js +2 -3
  10. package/dist/cli/react.js +16 -15
  11. package/dist/config/generateSettings.js +2 -2
  12. package/dist/config/validateSettings.d.ts +1 -1
  13. package/dist/config/validateSettings.js +4 -4
  14. package/dist/console/logger.d.ts +27 -0
  15. package/dist/console/logger.js +255 -0
  16. package/dist/console/logging.d.ts +1 -11
  17. package/dist/console/logging.js +24 -55
  18. package/dist/formats/files/save.js +2 -2
  19. package/dist/formats/files/translate.js +8 -8
  20. package/dist/formats/files/upload.js +7 -6
  21. package/dist/formats/gt/save.js +4 -3
  22. package/dist/formats/json/flattenJson.js +3 -3
  23. package/dist/formats/json/mergeJson.d.ts +1 -1
  24. package/dist/formats/json/mergeJson.js +69 -21
  25. package/dist/formats/json/parseJson.js +14 -13
  26. package/dist/formats/json/utils.js +16 -15
  27. package/dist/formats/yaml/mergeYaml.js +6 -5
  28. package/dist/formats/yaml/parseYaml.js +4 -3
  29. package/dist/formats/yaml/utils.js +4 -3
  30. package/dist/fs/clearLocaleDirs.js +6 -6
  31. package/dist/fs/config/downloadedVersions.js +3 -3
  32. package/dist/fs/config/parseFilesConfig.js +2 -2
  33. package/dist/fs/config/setupConfig.js +2 -2
  34. package/dist/fs/config/updateConfig.js +2 -2
  35. package/dist/fs/config/updateVersions.js +3 -3
  36. package/dist/fs/copyFile.js +2 -2
  37. package/dist/fs/createLoadTranslationsFile.js +3 -3
  38. package/dist/fs/determineFramework.js +3 -3
  39. package/dist/fs/findFilepath.js +5 -4
  40. package/dist/hooks/postProcess.js +9 -9
  41. package/dist/next/parse/handleInitGT.js +2 -2
  42. package/dist/react/parse/addVitePlugin/index.js +4 -3
  43. package/dist/react/parse/addVitePlugin/installCompiler.js +2 -2
  44. package/dist/react/parse/addVitePlugin/updateViteConfig.js +9 -12
  45. package/dist/react/parse/createDictionaryUpdates.js +4 -3
  46. package/dist/react/parse/createInlineUpdates.js +2 -2
  47. package/dist/setup/wizard.js +17 -16
  48. package/dist/translation/parse.js +4 -3
  49. package/dist/translation/stage.js +4 -4
  50. package/dist/translation/validate.js +6 -6
  51. package/dist/types/index.d.ts +1 -0
  52. package/dist/utils/addExplicitAnchorIds.js +2 -2
  53. package/dist/utils/credentials.js +4 -3
  54. package/dist/utils/installPackage.js +11 -11
  55. package/dist/utils/packageJson.js +4 -3
  56. package/dist/workflow/BranchStep.js +5 -4
  57. package/dist/workflow/DownloadStep.js +5 -5
  58. package/dist/workflow/EnqueueStep.js +2 -2
  59. package/dist/workflow/PollJobsStep.js +3 -3
  60. package/dist/workflow/SetupStep.js +2 -2
  61. package/dist/workflow/UploadStep.js +3 -3
  62. package/dist/workflow/UserEditDiffsStep.js +2 -2
  63. package/dist/workflow/download.js +4 -3
  64. package/dist/workflow/stage.js +5 -4
  65. package/package.json +2 -2
  66. package/dist/utils/SpinnerManager.d.ts +0 -30
  67. package/dist/utils/SpinnerManager.js +0 -73
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.5.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#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
8
+
9
+ ## 2.5.7
10
+
11
+ ### Patch Changes
12
+
13
+ - [#819](https://github.com/generaltranslation/gt/pull/819) [`50338d2`](https://github.com/generaltranslation/gt/commit/50338d2192e2882a4192273a7bbf12d39939c209) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Adding sorting by locale order
14
+
3
15
  ## 2.5.6
4
16
 
5
17
  ### 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
  }
@@ -83,7 +83,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
83
83
  translatedContent: file.data,
84
84
  targetLocale: locale,
85
85
  },
86
- ], options.defaultLocale)[0];
86
+ ], options.defaultLocale, options.locales)[0];
87
87
  }
88
88
  }
89
89
  }
@@ -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
  }
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';
@@ -55,7 +56,7 @@ export class BaseCLI {
55
56
  .description('Submits the project to the General Translation API for translation. Translations created using this command will require human approval.')).action(async (initOptions) => {
56
57
  displayHeader('Staging project for translation with approval required...');
57
58
  await this.handleStage(initOptions);
58
- endCommand('Done!');
59
+ logger.endCommand('Done!');
59
60
  });
60
61
  }
61
62
  setupTranslateCommand() {
@@ -64,7 +65,7 @@ export class BaseCLI {
64
65
  .description('Translate your project using General Translation')).action(async (initOptions) => {
65
66
  displayHeader('Starting translation...');
66
67
  await this.handleTranslate(initOptions);
67
- endCommand('Done!');
68
+ logger.endCommand('Done!');
68
69
  });
69
70
  }
70
71
  setupSendDiffsCommand() {
@@ -76,7 +77,7 @@ export class BaseCLI {
76
77
  const config = findFilepath(['gt.config.json']);
77
78
  const settings = await generateSettings({ config });
78
79
  await saveLocalEdits(settings);
79
- endCommand('Saved local edits');
80
+ logger.endCommand('Saved local edits');
80
81
  });
81
82
  }
82
83
  async handleStage(initOptions) {
@@ -126,7 +127,7 @@ export class BaseCLI {
126
127
  const settings = await generateSettings(initOptions);
127
128
  const options = { ...initOptions, ...settings };
128
129
  await this.handleUploadCommand(options);
129
- endCommand('Done!');
130
+ logger.endCommand('Done!');
130
131
  });
131
132
  }
132
133
  setupLoginCommand() {
@@ -159,7 +160,7 @@ export class BaseCLI {
159
160
  }
160
161
  }
161
162
  await this.handleLoginCommand(options);
162
- endCommand(`Done! A ${options.keyType} key has been generated and saved to your .env.local file.`);
163
+ logger.endCommand(`Done! A ${options.keyType} key has been generated and saved to your .env.local file.`);
163
164
  });
164
165
  }
165
166
  setupInitCommand() {
@@ -179,20 +180,20 @@ export class BaseCLI {
179
180
  defaultValue: true,
180
181
  });
181
182
  if (wrap) {
182
- logInfo(`${chalk.yellow('[EXPERIMENTAL]')} Running React setup wizard...`);
183
+ logger.info(`${chalk.yellow('[EXPERIMENTAL]')} Running React setup wizard...`);
183
184
  await this.handleSetupReactCommand(options);
184
- endCommand(`Done! Since this wizard is experimental, please review the changes and make modifications as needed.
185
+ logger.endCommand(`Done! Since this wizard is experimental, please review the changes and make modifications as needed.
185
186
  Certain aspects of your app may still need manual setup.
186
187
  See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`);
187
188
  ranReactSetup = true;
188
189
  }
189
190
  }
190
191
  if (ranReactSetup) {
191
- startCommand('Setting up project config...');
192
+ logger.startCommand('Setting up project config...');
192
193
  }
193
194
  // Configure gt.config.json
194
195
  await this.handleInitCommand(ranReactSetup);
195
- endCommand('Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs');
196
+ logger.endCommand('Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs');
196
197
  });
197
198
  }
198
199
  setupConfigureCommand() {
@@ -201,10 +202,10 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
201
202
  .description('Configure your project for General Translation. This will create a gt.config.json file in your codebase.')
202
203
  .action(async () => {
203
204
  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.');
205
+ 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
206
  // Configure gt.config.json
206
207
  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
+ 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');
208
209
  });
209
210
  }
210
211
  setupSetupCommand() {
@@ -216,7 +217,7 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
216
217
  .action(async (options) => {
217
218
  displayHeader('Running React setup wizard...');
218
219
  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");
220
+ logger.endCommand("Done! Take advantage of all of General Translation's features by signing up for a free account! https://generaltranslation.com/signup");
220
221
  });
221
222
  }
222
223
  async handleUploadCommand(settings) {
@@ -279,7 +280,7 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
279
280
  if (isUsingGT && !usingCDN) {
280
281
  // Create loadTranslations.js file for local translations
281
282
  await createLoadTranslationsFile(process.cwd(), finalTranslationsDir);
282
- logMessage(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.
283
+ logger.message(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.
283
284
  Make sure to add this function to your app configuration.
284
285
  See https://generaltranslation.com/en/docs/next/guides/local-tx`);
285
286
  }
@@ -325,14 +326,14 @@ See https://generaltranslation.com/en/docs/next/guides/local-tx`);
325
326
  files: Object.keys(files).length > 0 ? files : undefined,
326
327
  publish: isUsingGT && usingCDN,
327
328
  });
328
- logSuccess(`Feel free to edit ${chalk.cyan(configFilepath)} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
329
+ logger.success(`Feel free to edit ${chalk.cyan(configFilepath)} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
329
330
  // Install gtx-cli if not installed
330
331
  const isCLIInstalled = packageJson
331
332
  ? isPackageInstalled('gtx-cli', packageJson, true, true)
332
333
  : true; // if no package.json, we can't install it
333
334
  if (!isCLIInstalled) {
334
335
  const packageManager = await getPackageManager();
335
- const spinner = createSpinner();
336
+ const spinner = logger.createSpinner();
336
337
  spinner.start(`Installing gtx-cli as a dev dependency with ${packageManager.name}...`);
337
338
  await installPackage('gtx-cli', packageManager, true);
338
339
  spinner.stop(chalk.green('Installed gtx-cli.'));
@@ -1,4 +1,5 @@
1
- import { logErrorAndExit, logSuccess } from '../../console/logging.js';
1
+ import { logger } from '../../console/logger.js';
2
+ import { logErrorAndExit } from '../../console/logging.js';
2
3
  import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, invalidConfigurationError, } from '../../console/index.js';
3
4
  import { aggregateFiles } from '../../formats/files/translate.js';
4
5
  import { aggregateReactTranslations } from '../../translation/stage.js';
@@ -12,19 +13,19 @@ export async function handleStage(options, settings, library, stage) {
12
13
  // Validate required settings are present if not in dry run
13
14
  if (!options.dryRun) {
14
15
  if (!settings.locales) {
15
- logErrorAndExit(noLocalesError);
16
+ return logErrorAndExit(noLocalesError);
16
17
  }
17
18
  if (!settings.defaultLocale) {
18
- logErrorAndExit(noDefaultLocaleError);
19
+ return logErrorAndExit(noDefaultLocaleError);
19
20
  }
20
21
  if (!settings.apiKey) {
21
- logErrorAndExit(noApiKeyError);
22
+ return logErrorAndExit(noApiKeyError);
22
23
  }
23
24
  if (settings.apiKey.startsWith('gtx-dev-')) {
24
- logErrorAndExit(devApiKeyError);
25
+ return logErrorAndExit(devApiKeyError);
25
26
  }
26
27
  if (!settings.projectId) {
27
- logErrorAndExit(noProjectIdError);
28
+ return logErrorAndExit(noProjectIdError);
28
29
  }
29
30
  }
30
31
  // Aggregate files
@@ -77,7 +78,7 @@ export async function handleStage(options, settings, library, stage) {
77
78
  return `- ${file.fileName}`;
78
79
  })
79
80
  .join('\n');
80
- logSuccess(`Dry run: No files were sent to General Translation. Found files:\n${fileNames}`);
81
+ logger.success(`Dry run: No files were sent to General Translation. Found files:\n${fileNames}`);
81
82
  return null;
82
83
  }
83
84
  // 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/react.js CHANGED
@@ -1,4 +1,5 @@
1
- import { displayHeader, endCommand, logError, logStep, logSuccess, logWarning, promptConfirm, } from '../console/logging.js';
1
+ import { displayHeader, exitSync, promptConfirm } from '../console/logging.js';
2
+ import { logger } from '../console/logger.js';
2
3
  import loadJSON from '../fs/loadJSON.js';
3
4
  import findFilepath from '../fs/findFilepath.js';
4
5
  import chalk from 'chalk';
@@ -37,7 +38,7 @@ export class ReactCLI extends BaseCLI {
37
38
  .description('Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'))).action(async (options) => {
38
39
  displayHeader('Staging project for translation with approval required...');
39
40
  await this.handleStage(options);
40
- endCommand('Done!');
41
+ logger.endCommand('Done!');
41
42
  });
42
43
  }
43
44
  setupTranslateCommand() {
@@ -46,7 +47,7 @@ export class ReactCLI extends BaseCLI {
46
47
  .description('Scans the project for a dictionary and/or <T> tags, and sends the updates to the General Translation API for translation.'))).action(async (options) => {
47
48
  displayHeader('Translating project...');
48
49
  await this.handleTranslate(options);
49
- endCommand('Done!');
50
+ logger.endCommand('Done!');
50
51
  });
51
52
  }
52
53
  setupValidateCommand() {
@@ -62,7 +63,7 @@ export class ReactCLI extends BaseCLI {
62
63
  // intro here since we don't want to show the ascii title
63
64
  intro(chalk.cyan('Validating project...'));
64
65
  await this.handleValidate(options, files);
65
- endCommand('Done!');
66
+ logger.endCommand('Done!');
66
67
  });
67
68
  }
68
69
  setupGenerateSourceCommand() {
@@ -71,7 +72,7 @@ export class ReactCLI extends BaseCLI {
71
72
  .description('Generate a translation file for the source locale. This command should be used if you are handling your own translations.'))).action(async (initOptions) => {
72
73
  displayHeader('Generating source templates...');
73
74
  await this.handleGenerateSourceCommand(initOptions);
74
- endCommand('Done!');
75
+ logger.endCommand('Done!');
75
76
  });
76
77
  }
77
78
  async handleGenerateSourceCommand(initOptions) {
@@ -93,11 +94,11 @@ export class ReactCLI extends BaseCLI {
93
94
  if (settings.files && settings.files.placeholderPaths.gt) {
94
95
  const translationFiles = resolveLocaleFiles(settings.files.placeholderPaths, settings.defaultLocale);
95
96
  if (!translationFiles.gt) {
96
- logError(noFilesError);
97
- process.exit(1);
97
+ logger.error(noFilesError);
98
+ exitSync(1);
98
99
  }
99
100
  await saveJSON(translationFiles.gt, newData);
100
- logStep('Source file saved successfully!');
101
+ logger.step('Source file saved successfully!');
101
102
  // Also save translations (after merging with existing translations)
102
103
  for (const locale of settings.locales) {
103
104
  const translationsFile = resolveLocaleFiles(settings.files.placeholderPaths, locale);
@@ -113,7 +114,7 @@ export class ReactCLI extends BaseCLI {
113
114
  const filteredTranslations = Object.fromEntries(Object.entries(mergedTranslations).filter(([key]) => newData[key]));
114
115
  await saveJSON(translationsFile.gt, filteredTranslations);
115
116
  }
116
- logStep('Merged translations successfully!');
117
+ logger.step('Merged translations successfully!');
117
118
  }
118
119
  }
119
120
  async handleScanCommand(options) {
@@ -123,8 +124,8 @@ export class ReactCLI extends BaseCLI {
123
124
  defaultValue: true,
124
125
  });
125
126
  if (!answer) {
126
- logError('Operation cancelled.');
127
- process.exit(0);
127
+ logger.error('Operation cancelled.');
128
+ exitSync(0);
128
129
  }
129
130
  // ----- Create a starter gt.config.json file -----
130
131
  await generateSettings(options);
@@ -139,18 +140,18 @@ export class ReactCLI extends BaseCLI {
139
140
  // Wrap all JSX elements in the src directory with a <T> tag, with unique ids
140
141
  const { filesUpdated } = await this.wrapContent(options, 'react', errors, warnings);
141
142
  if (errors.length > 0) {
142
- logError(chalk.red('Failed to write files:\n') + errors.join('\n'));
143
+ logger.error(chalk.red('Failed to write files:\n') + errors.join('\n'));
143
144
  }
144
145
  // Format updated files if formatters are available
145
146
  if (!options.disableFormatting)
146
147
  await formatFiles(filesUpdated);
147
- logSuccess(`Success! Added <T> tags and updated ${chalk.bold.cyan(filesUpdated.length)} files:\n` +
148
+ logger.success(`Success! Added <T> tags and updated ${chalk.bold.cyan(filesUpdated.length)} files:\n` +
148
149
  filesUpdated.map((file) => `${chalk.green('-')} ${file}`).join('\n'));
149
150
  if (filesUpdated.length > 0) {
150
- logStep(chalk.green('Please verify the changes before committing.'));
151
+ logger.step(chalk.green('Please verify the changes before committing.'));
151
152
  }
152
153
  if (warnings.length > 0) {
153
- logWarning(chalk.yellow('Warnings encountered:') +
154
+ logger.warn(chalk.yellow('Warnings encountered:') +
154
155
  '\n' +
155
156
  warnings
156
157
  .map((warning) => `${chalk.yellow('-')} ${warning}`)
@@ -1,4 +1,4 @@
1
- import { displayProjectId, logErrorAndExit, warnApiKeyInConfig, } from '../console/logging.js';
1
+ import { displayProjectId, exitSync, logErrorAndExit, warnApiKeyInConfig, } from '../console/logging.js';
2
2
  import { loadConfig } from '../fs/config/loadConfig.js';
3
3
  import { defaultBaseUrl, libraryDefaultLocale, } from 'generaltranslation/internal';
4
4
  import fs from 'node:fs';
@@ -46,7 +46,7 @@ export async function generateSettings(flags, cwd = process.cwd()) {
46
46
  // Warn if apiKey is present in gt.config.json
47
47
  if (gtConfig.apiKey) {
48
48
  warnApiKeyInConfig(flags.config);
49
- process.exit(1);
49
+ exitSync(1);
50
50
  }
51
51
  const projectIdEnv = resolveProjectId();
52
52
  // Resolve mismatched projectIds
@@ -1,3 +1,3 @@
1
1
  import { Settings } from '../types/index.js';
2
- export declare function validateSettings(settings: Settings): void;
2
+ export declare function validateSettings(settings: Settings): undefined;
3
3
  export declare function validateConfigExists(): string;
@@ -6,19 +6,19 @@ export function validateSettings(settings) {
6
6
  // Validate locales
7
7
  for (const locale of settings.locales) {
8
8
  if (!isValidLocale(locale, settings.customMapping)) {
9
- logErrorAndExit(`Provided locales: "${settings?.locales?.join()}", ${locale} is not a valid locale!`);
9
+ return logErrorAndExit(`Provided locales: "${settings?.locales?.join()}", ${locale} is not a valid locale!`);
10
10
  }
11
11
  }
12
12
  if (settings.defaultLocale &&
13
13
  !isValidLocale(settings.defaultLocale, settings.customMapping)) {
14
- logErrorAndExit(`defaultLocale: ${settings.defaultLocale} is not a valid locale!`);
14
+ return logErrorAndExit(`defaultLocale: ${settings.defaultLocale} is not a valid locale!`);
15
15
  }
16
16
  // defaultLocale cannot be a superset of any other locale
17
17
  if (settings.defaultLocale &&
18
18
  settings.locales.some((locale) => isSupersetLocale(settings.defaultLocale, locale) &&
19
19
  !isSupersetLocale(locale, settings.defaultLocale))) {
20
20
  const locale = settings.locales.find((locale) => isSupersetLocale(settings.defaultLocale, locale));
21
- logErrorAndExit(`defaultLocale: ${settings.defaultLocale} is a superset of another locale (${locale})! Please change the defaultLocale to a more specific locale.`);
21
+ return logErrorAndExit(`defaultLocale: ${settings.defaultLocale} is a superset of another locale (${locale})! Please change the defaultLocale to a more specific locale.`);
22
22
  }
23
23
  }
24
24
  export function validateConfigExists() {
@@ -28,5 +28,5 @@ export function validateConfigExists() {
28
28
  return possibleConfigPath;
29
29
  }
30
30
  }
31
- logErrorAndExit('No gt.config.json file found. Are you in the correct directory?');
31
+ return logErrorAndExit('No gt.config.json file found. Are you in the correct directory?');
32
32
  }
@@ -0,0 +1,27 @@
1
+ import type { SpinnerResult, ProgressResult } from '@clack/prompts';
2
+ export type LogFormat = 'default' | 'json';
3
+ declare class Logger {
4
+ private static instance;
5
+ private pinoLogger;
6
+ private fileLogger;
7
+ private logFormat;
8
+ private constructor();
9
+ static getInstance(): Logger;
10
+ trace(message: string): void;
11
+ debug(message: string): void;
12
+ info(message: string): void;
13
+ warn(message: string): void;
14
+ error(message: string): void;
15
+ fatal(message: string): void;
16
+ silent(message: string): void;
17
+ success(message: string): void;
18
+ step(message: string): void;
19
+ message(message: string, symbol?: string): void;
20
+ createSpinner(indicator?: 'dots' | 'timer'): SpinnerResult;
21
+ createProgressBar(total: number): ProgressResult;
22
+ startCommand(message: string): void;
23
+ endCommand(message: string): void;
24
+ flush(): void;
25
+ }
26
+ export declare const logger: Logger;
27
+ export {};