gtx-cli 2.5.7 → 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 (65) hide show
  1. package/CHANGELOG.md +6 -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.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.js +19 -18
  24. package/dist/formats/json/parseJson.js +14 -13
  25. package/dist/formats/json/utils.js +16 -15
  26. package/dist/formats/yaml/mergeYaml.js +6 -5
  27. package/dist/formats/yaml/parseYaml.js +4 -3
  28. package/dist/formats/yaml/utils.js +4 -3
  29. package/dist/fs/clearLocaleDirs.js +6 -6
  30. package/dist/fs/config/downloadedVersions.js +3 -3
  31. package/dist/fs/config/parseFilesConfig.js +2 -2
  32. package/dist/fs/config/setupConfig.js +2 -2
  33. package/dist/fs/config/updateConfig.js +2 -2
  34. package/dist/fs/config/updateVersions.js +3 -3
  35. package/dist/fs/copyFile.js +2 -2
  36. package/dist/fs/createLoadTranslationsFile.js +3 -3
  37. package/dist/fs/determineFramework.js +3 -3
  38. package/dist/fs/findFilepath.js +5 -4
  39. package/dist/hooks/postProcess.js +9 -9
  40. package/dist/next/parse/handleInitGT.js +2 -2
  41. package/dist/react/parse/addVitePlugin/index.js +4 -3
  42. package/dist/react/parse/addVitePlugin/installCompiler.js +2 -2
  43. package/dist/react/parse/addVitePlugin/updateViteConfig.js +9 -12
  44. package/dist/react/parse/createDictionaryUpdates.js +4 -3
  45. package/dist/react/parse/createInlineUpdates.js +2 -2
  46. package/dist/setup/wizard.js +17 -16
  47. package/dist/translation/parse.js +4 -3
  48. package/dist/translation/stage.js +4 -4
  49. package/dist/translation/validate.js +6 -6
  50. package/dist/utils/addExplicitAnchorIds.js +2 -2
  51. package/dist/utils/credentials.js +4 -3
  52. package/dist/utils/installPackage.js +11 -11
  53. package/dist/utils/packageJson.js +4 -3
  54. package/dist/workflow/BranchStep.js +5 -4
  55. package/dist/workflow/DownloadStep.js +5 -5
  56. package/dist/workflow/EnqueueStep.js +2 -2
  57. package/dist/workflow/PollJobsStep.js +3 -3
  58. package/dist/workflow/SetupStep.js +2 -2
  59. package/dist/workflow/UploadStep.js +3 -3
  60. package/dist/workflow/UserEditDiffsStep.js +2 -2
  61. package/dist/workflow/download.js +4 -3
  62. package/dist/workflow/stage.js +5 -4
  63. package/package.json +2 -2
  64. package/dist/utils/SpinnerManager.d.ts +0 -30
  65. package/dist/utils/SpinnerManager.js +0 -73
@@ -6,7 +6,7 @@ import traverseModule from '@babel/traverse';
6
6
  const traverse = traverseModule.default || traverseModule;
7
7
  const generate = generateModule.default || generateModule;
8
8
  import * as t from '@babel/types';
9
- import { logError } from '../../console/logging.js';
9
+ import { logger } from '../../console/logger.js';
10
10
  import { needsCJS } from '../../utils/parse/needsCJS.js';
11
11
  export async function handleInitGT(filepath, errors, warnings, filesUpdated, packageJson, tsconfigJson) {
12
12
  const code = await fs.promises.readFile(filepath, 'utf8');
@@ -151,7 +151,7 @@ export async function handleInitGT(filepath, errors, warnings, filesUpdated, pac
151
151
  filesUpdated.push(filepath);
152
152
  }
153
153
  catch (error) {
154
- logError(`Error parsing file ${filepath}: ${error}`);
154
+ logger.error(`Error parsing file ${filepath}: ${error}`);
155
155
  errors.push(`Failed to parse ${filepath}: ${error}`);
156
156
  }
157
157
  }
@@ -1,7 +1,8 @@
1
1
  import findFilepath from '../../../fs/findFilepath.js';
2
- import { logError } from '../../../console/logging.js';
2
+ import { logger } from '../../../console/logger.js';
3
3
  import { installCompiler } from './installCompiler.js';
4
4
  import { updateViteConfig } from './updateViteConfig.js';
5
+ import { exitSync } from '../../../console/logging.js';
5
6
  const VITE_CONFIG_PATH_BASE = './vite.config.';
6
7
  /**
7
8
  * Adds the gt compiler plugin to the vite config file
@@ -17,13 +18,13 @@ export async function addVitePlugin({ errors, warnings, filesUpdated, packageJso
17
18
  VITE_CONFIG_PATH_BASE + 'cts',
18
19
  ]);
19
20
  if (!viteConfigPath) {
20
- logError(`No ${VITE_CONFIG_PATH_BASE}[js|ts|mjs|mts|cjs|cts] file found. Please add the @generaltranslation/compiler plugin to your vite configuration file:
21
+ logger.error(`No ${VITE_CONFIG_PATH_BASE}[js|ts|mjs|mts|cjs|cts] file found. Please add the @generaltranslation/compiler plugin to your vite configuration file:
21
22
  import { vite as gtCompiler } from '@generaltranslation/compiler';
22
23
  export default defineConfig({
23
24
  plugins: [gtCompiler()],
24
25
  });
25
26
  `);
26
- process.exit(1);
27
+ exitSync(1);
27
28
  }
28
29
  // Install @generaltranslation/compiler if not installed
29
30
  await installCompiler({ packageJson });
@@ -1,4 +1,4 @@
1
- import { createSpinner } from '../../../console/logging.js';
1
+ import { logger } from '../../../console/logger.js';
2
2
  import { installPackage } from '../../../utils/installPackage.js';
3
3
  import { isPackageInstalled } from '../../../utils/packageJson.js';
4
4
  import { getPackageManager } from '../../../utils/packageManager.js';
@@ -12,7 +12,7 @@ export async function installCompiler({ packageJson, }) {
12
12
  return;
13
13
  }
14
14
  // Animation
15
- const spinner = createSpinner();
15
+ const spinner = logger.createSpinner();
16
16
  spinner.start(`Installing @generaltranslation/compiler...`);
17
17
  // Install
18
18
  const packageManager = await getPackageManager();
@@ -1,5 +1,4 @@
1
- import { createSpinner } from '../../../console/logging.js';
2
- import { logError } from '../../../console/logging.js';
1
+ import { logger } from '../../../console/logger.js';
3
2
  import fs from 'node:fs';
4
3
  import chalk from 'chalk';
5
4
  import generateModule from '@babel/generator';
@@ -9,6 +8,7 @@ import { addCompilerImport } from './utils/addCompilerImport.js';
9
8
  import { checkCompilerImport } from './utils/checkCompilerImport.js';
10
9
  import { checkPluginInvocation } from './utils/checkPluginInvocation.js';
11
10
  import { addPluginInvocation } from './utils/addPluginInvocation.js';
11
+ import { exitSync } from '../../../console/logging.js';
12
12
  // Handle CommonJS/ESM interop
13
13
  const generate = generateModule.default || generateModule;
14
14
  /**
@@ -18,7 +18,7 @@ const generate = generateModule.default || generateModule;
18
18
  */
19
19
  export async function updateViteConfig({ errors, warnings, filesUpdated, viteConfigPath, packageJson, tsconfigJson, }) {
20
20
  // Animation
21
- const spinner = createSpinner();
21
+ const spinner = logger.createSpinner();
22
22
  spinner.start(`Adding gt compiler plugin to ${viteConfigPath}...`);
23
23
  // Read the file
24
24
  let code;
@@ -26,9 +26,8 @@ export async function updateViteConfig({ errors, warnings, filesUpdated, viteCon
26
26
  code = await fs.promises.readFile(viteConfigPath, 'utf8');
27
27
  }
28
28
  catch (error) {
29
- logError(`Error: Failed to read ${viteConfigPath}: ${error}`);
30
- process.exit(1);
31
- return;
29
+ logger.error(`Error: Failed to read ${viteConfigPath}: ${error}`);
30
+ exitSync(1);
32
31
  }
33
32
  // Update the ast
34
33
  let updatedCode, success;
@@ -43,9 +42,8 @@ export async function updateViteConfig({ errors, warnings, filesUpdated, viteCon
43
42
  }));
44
43
  }
45
44
  catch (error) {
46
- logError(`Error: Failed to update ${viteConfigPath}: ${error}`);
47
- process.exit(1);
48
- return;
45
+ logger.error(`Error: Failed to update ${viteConfigPath}: ${error}`);
46
+ exitSync(1);
49
47
  }
50
48
  // Write the file
51
49
  try {
@@ -53,9 +51,8 @@ export async function updateViteConfig({ errors, warnings, filesUpdated, viteCon
53
51
  filesUpdated.push(viteConfigPath);
54
52
  }
55
53
  catch (error) {
56
- logError(`Error: Failed to write ${viteConfigPath}: ${error}`);
57
- process.exit(1);
58
- return;
54
+ logger.error(`Error: Failed to write ${viteConfigPath}: ${error}`);
55
+ exitSync(1);
59
56
  }
60
57
  // Animation
61
58
  spinner.stop(success
@@ -6,10 +6,11 @@ import flattenDictionary from '../utils/flattenDictionary.js';
6
6
  import loadJSON from '../../fs/loadJSON.js';
7
7
  import { hashSource } from 'generaltranslation/id';
8
8
  import getEntryAndMetadata from '../utils/getEntryAndMetadata.js';
9
- import { logError } from '../../console/logging.js';
9
+ import { logger } from '../../console/logger.js';
10
10
  import { randomUUID } from 'node:crypto';
11
11
  import { isValidIcu } from '../jsx/evaluateJsx.js';
12
12
  import { warnInvalidIcuSync } from '../../console/index.js';
13
+ import { exitSync } from '../../console/logging.js';
13
14
  export async function createDictionaryUpdates(dictionaryPath, warnings, esbuildConfig) {
14
15
  let dictionary;
15
16
  // ---- HANDLE JSON STRING DICTIONARY ----- //
@@ -32,8 +33,8 @@ export async function createDictionaryUpdates(dictionaryPath, warnings, esbuildC
32
33
  dictionaryModule = await import(tempFilePath);
33
34
  }
34
35
  catch (error) {
35
- logError(`Failed to load the bundled dictionary code: ${error}`);
36
- process.exit(1);
36
+ logger.error(`Failed to load the bundled dictionary code: ${error}`);
37
+ exitSync(1);
37
38
  }
38
39
  finally {
39
40
  // Clean up the temporary file
@@ -3,7 +3,7 @@ import { parse } from '@babel/parser';
3
3
  import { hashSource } from 'generaltranslation/id';
4
4
  import { parseTranslationComponent } from '../jsx/utils/jsxParsing/parseJsx.js';
5
5
  import { parseStrings } from '../jsx/utils/parseStringFunction.js';
6
- import { logError } from '../../console/logging.js';
6
+ import { logger } from '../../console/logger.js';
7
7
  import { matchFiles } from '../../fs/matchFiles.js';
8
8
  import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
9
9
  import { getPathsAndAliases } from '../jsx/utils/getPathsAndAliases.js';
@@ -23,7 +23,7 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
23
23
  });
24
24
  }
25
25
  catch (error) {
26
- logError(`Error parsing file ${file}: ${error}`);
26
+ logger.error(`Error parsing file ${file}: ${error}`);
27
27
  continue;
28
28
  }
29
29
  // First pass: collect imports and process translation functions
@@ -1,6 +1,6 @@
1
1
  import { detectFormatter } from '../hooks/postProcess.js';
2
- import { createSpinner, promptSelect } from '../console/logging.js';
3
- import { logInfo, logError, logStep, logWarning } from '../console/logging.js';
2
+ import { promptSelect } from '../console/logging.js';
3
+ import { logger } from '../console/logger.js';
4
4
  import chalk from 'chalk';
5
5
  import { promptConfirm } from '../console/logging.js';
6
6
  import findFilepath from '../fs/findFilepath.js';
@@ -13,6 +13,7 @@ import { installPackage } from '../utils/installPackage.js';
13
13
  import { createOrUpdateConfig } from '../fs/config/setupConfig.js';
14
14
  import { loadConfig } from '../fs/config/loadConfig.js';
15
15
  import { addVitePlugin } from '../react/parse/addVitePlugin/index.js';
16
+ import { exitSync } from '../console/logging.js';
16
17
  export async function handleSetupReactCommand(options) {
17
18
  // Ask user for confirmation using inquirer
18
19
  const answer = await promptConfirm({
@@ -24,8 +25,8 @@ Make sure you have committed or stashed any changes. Do you want to continue?`),
24
25
  cancelMessage: 'Operation cancelled. You can re-run this wizard with: npx gtx-cli setup',
25
26
  });
26
27
  if (!answer) {
27
- logInfo('Operation cancelled. You can re-run this wizard with: npx gtx-cli setup');
28
- process.exit(0);
28
+ logger.info('Operation cancelled. You can re-run this wizard with: npx gtx-cli setup');
29
+ exitSync(0);
29
30
  }
30
31
  const frameworkType = await promptSelect({
31
32
  message: 'What framework are you using?',
@@ -41,9 +42,9 @@ Make sure you have committed or stashed any changes. Do you want to continue?`),
41
42
  defaultValue: 'next-app',
42
43
  });
43
44
  if (frameworkType === 'other') {
44
- logError(`Sorry, other React frameworks are not currently supported.
45
+ logger.error(`Sorry, other React frameworks are not currently supported.
45
46
  Please let us know what you would like to see supported at https://github.com/generaltranslation/gt/issues`);
46
- process.exit(0);
47
+ exitSync(0);
47
48
  }
48
49
  // ----- Create a starter gt.config.json file -----
49
50
  await createOrUpdateConfig(options.config || 'gt.config.json', {
@@ -51,14 +52,14 @@ Please let us know what you would like to see supported at https://github.com/ge
51
52
  });
52
53
  const packageJson = await getPackageJson();
53
54
  if (!packageJson) {
54
- logError(chalk.red('No package.json found in the current directory. Please run this command from the root of your project.'));
55
- process.exit(1);
55
+ logger.error(chalk.red('No package.json found in the current directory. Please run this command from the root of your project.'));
56
+ exitSync(1);
56
57
  }
57
58
  // Check if gt-next or gt-react is installed
58
59
  if (frameworkType === 'next-app' &&
59
60
  !isPackageInstalled('gt-next', packageJson)) {
60
61
  const packageManager = await getPackageManager();
61
- const spinner = createSpinner('timer');
62
+ const spinner = logger.createSpinner('timer');
62
63
  spinner.start(`Installing gt-next with ${packageManager.name}...`);
63
64
  await installPackage('gt-next', packageManager);
64
65
  spinner.stop(chalk.green('Automatically installed gt-next.'));
@@ -66,7 +67,7 @@ Please let us know what you would like to see supported at https://github.com/ge
66
67
  else if (['next-pages', 'react', 'redwood', 'vite', 'gatsby'].includes(frameworkType) &&
67
68
  !isPackageInstalled('gt-react', packageJson)) {
68
69
  const packageManager = await getPackageManager();
69
- const spinner = createSpinner('timer');
70
+ const spinner = logger.createSpinner('timer');
70
71
  spinner.start(`Installing gt-react with ${packageManager.name}...`);
71
72
  await installPackage('gt-react', packageManager);
72
73
  spinner.stop(chalk.green('Automatically installed gt-react.'));
@@ -86,8 +87,8 @@ Please let us know what you would like to see supported at https://github.com/ge
86
87
  './next.config.mts',
87
88
  ]);
88
89
  if (!nextConfigPath) {
89
- logError('No next.config.[js|ts|mjs|mts] file found.');
90
- process.exit(1);
90
+ logger.error('No next.config.[js|ts|mjs|mts] file found.');
91
+ exitSync(1);
91
92
  }
92
93
  const mergeOptions = {
93
94
  ...options,
@@ -96,7 +97,7 @@ Please let us know what you would like to see supported at https://github.com/ge
96
97
  skipTs: true,
97
98
  addGTProvider: true,
98
99
  };
99
- const spinner = createSpinner();
100
+ const spinner = logger.createSpinner();
100
101
  spinner.start('Wrapping JSX content with <T> tags...');
101
102
  // Wrap all JSX elements in the src directory with a <T> tag, with unique ids
102
103
  const { filesUpdated: filesUpdatedNext } = await wrapContentNext(mergeOptions, 'gt-next', errors, warnings);
@@ -104,7 +105,7 @@ Please let us know what you would like to see supported at https://github.com/ge
104
105
  spinner.stop(chalk.green(`Success! Updated ${chalk.bold.cyan(filesUpdated.length)} files:\n`) + filesUpdated.map((file) => `${chalk.green('-')} ${file}`).join('\n'));
105
106
  // Add the withGTConfig() function to the next.config.js file
106
107
  await handleInitGT(nextConfigPath, errors, warnings, filesUpdated, packageJson, tsconfigJson);
107
- logStep(chalk.green(`Added withGTConfig() to your ${nextConfigPath} file.`));
108
+ logger.step(chalk.green(`Added withGTConfig() to your ${nextConfigPath} file.`));
108
109
  }
109
110
  // Add gt compiler plugin
110
111
  if (frameworkType === 'vite') {
@@ -117,10 +118,10 @@ Please let us know what you would like to see supported at https://github.com/ge
117
118
  });
118
119
  }
119
120
  if (errors.length > 0) {
120
- logError(chalk.red('Failed to write files:\n') + errors.join('\n'));
121
+ logger.error(chalk.red('Failed to write files:\n') + errors.join('\n'));
121
122
  }
122
123
  if (warnings.length > 0) {
123
- logWarning(chalk.yellow('Warnings encountered:') +
124
+ logger.warn(chalk.yellow('Warnings encountered:') +
124
125
  '\n' +
125
126
  warnings.map((warning) => `${chalk.yellow('-')} ${warning}`).join('\n'));
126
127
  }
@@ -1,10 +1,11 @@
1
1
  import fs from 'fs';
2
- import { logError } from '../console/logging.js';
2
+ import { logger } from '../console/logger.js';
3
3
  import loadJSON from '../fs/loadJSON.js';
4
4
  import { createDictionaryUpdates } from '../react/parse/createDictionaryUpdates.js';
5
5
  import { createInlineUpdates } from '../react/parse/createInlineUpdates.js';
6
6
  import createESBuildConfig from '../react/config/createESBuildConfig.js';
7
7
  import chalk from 'chalk';
8
+ import { exitSync } from '../console/logging.js';
8
9
  /**
9
10
  * Searches for gt-react or gt-next dictionary files and creates updates for them,
10
11
  * as well as inline updates for <T> tags and useGT()/getGT() calls
@@ -33,8 +34,8 @@ export async function createUpdates(options, src, sourceDictionary, pkg, validat
33
34
  if (options.jsconfig) {
34
35
  const jsconfig = loadJSON(options.jsconfig);
35
36
  if (!jsconfig) {
36
- logError(`Failed to resolve jsconfig.json or tsconfig.json at provided filepath: "${options.jsconfig}"`);
37
- process.exit(1);
37
+ logger.error(`Failed to resolve jsconfig.json or tsconfig.json at provided filepath: "${options.jsconfig}"`);
38
+ exitSync(1);
38
39
  }
39
40
  esbuildConfig = createESBuildConfig(jsconfig);
40
41
  }
@@ -1,7 +1,7 @@
1
1
  import { logErrorAndExit } from '../console/logging.js';
2
2
  import chalk from 'chalk';
3
3
  import findFilepath from '../fs/findFilepath.js';
4
- import { logWarning, logError } from '../console/logging.js';
4
+ import { logger } from '../console/logger.js';
5
5
  import { createUpdates } from './parse.js';
6
6
  export async function aggregateReactTranslations(options, settings, library) {
7
7
  if (!options.dictionary) {
@@ -17,14 +17,14 @@ export async function aggregateReactTranslations(options, settings, library) {
17
17
  // ---- CREATING UPDATES ---- //
18
18
  const { updates, errors, warnings } = await createUpdates(options, settings.src, options.dictionary, library, false, settings.parsingOptions);
19
19
  if (warnings.length > 0) {
20
- logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.\n` +
20
+ logger.warn(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.\n` +
21
21
  warnings
22
22
  .map((warning) => chalk.yellow('• Warning: ') + chalk.white(warning))
23
23
  .join('\n')));
24
24
  }
25
25
  if (errors.length > 0) {
26
26
  if (options.ignoreErrors) {
27
- logWarning(chalk.yellow(`Warning: CLI tool encountered ${errors.length} syntax errors while scanning for translatable content. These components will not be translated.\n` +
27
+ logger.warn(chalk.yellow(`Warning: CLI tool encountered ${errors.length} syntax errors while scanning for translatable content. These components will not be translated.\n` +
28
28
  errors
29
29
  .map((error) => chalk.yellow('• ') + chalk.white(error) + '\n')
30
30
  .join('')));
@@ -37,7 +37,7 @@ export async function aggregateReactTranslations(options, settings, library) {
37
37
  }
38
38
  }
39
39
  if (updates.length == 0) {
40
- logError(chalk.red(`No in-line content or dictionaries were found for ${chalk.green(library)}. Are you sure you're running this command in the right directory?`));
40
+ logger.error(chalk.red(`No in-line content or dictionaries were found for ${chalk.green(library)}. Are you sure you're running this command in the right directory?`));
41
41
  return updates;
42
42
  }
43
43
  return updates;
@@ -1,7 +1,7 @@
1
- import { logErrorAndExit, logWarning } from '../console/logging.js';
1
+ import { logErrorAndExit } from '../console/logging.js';
2
2
  import chalk from 'chalk';
3
3
  import findFilepath from '../fs/findFilepath.js';
4
- import { logError, logSuccess } from '../console/logging.js';
4
+ import { logger } from '../console/logger.js';
5
5
  import { createUpdates } from './parse.js';
6
6
  import { createInlineUpdates } from '../react/parse/createInlineUpdates.js';
7
7
  export async function validateProject(settings, pkg, files) {
@@ -14,7 +14,7 @@ export async function validateProject(settings, pkg, files) {
14
14
  .map((error) => chalk.red('• ') + chalk.white(error) + '\n')
15
15
  .join('')));
16
16
  }
17
- logSuccess(chalk.green(`Success! Found ${updates.length} translatable entries.`));
17
+ logger.success(chalk.green(`Success! Found ${updates.length} translatable entries.`));
18
18
  return;
19
19
  }
20
20
  if (!settings.dictionary) {
@@ -29,7 +29,7 @@ export async function validateProject(settings, pkg, files) {
29
29
  }
30
30
  const { updates, errors, warnings } = await createUpdates(settings, settings.src, settings.dictionary, pkg, true, settings.parsingOptions);
31
31
  if (warnings.length > 0) {
32
- logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.`) +
32
+ logger.warn(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.`) +
33
33
  '\n' +
34
34
  warnings
35
35
  .map((warning) => chalk.yellow('• ') + chalk.white(warning))
@@ -42,9 +42,9 @@ export async function validateProject(settings, pkg, files) {
42
42
  .join('')));
43
43
  }
44
44
  if (updates.length === 0) {
45
- logError(chalk.red(`No in-line content or dictionaries were found for ${chalk.green(pkg)}. Are you sure you're running this command in the right directory?`));
45
+ logger.error(chalk.red(`No in-line content or dictionaries were found for ${chalk.green(pkg)}. Are you sure you're running this command in the right directory?`));
46
46
  }
47
47
  else {
48
- logSuccess(chalk.green(`Success! Found ${updates.length} translatable entries for ${chalk.green(pkg)}.`));
48
+ logger.success(chalk.green(`Success! Found ${updates.length} translatable entries for ${chalk.green(pkg)}.`));
49
49
  }
50
50
  }
@@ -4,7 +4,7 @@ import remarkMdx from 'remark-mdx';
4
4
  import remarkFrontmatter from 'remark-frontmatter';
5
5
  import remarkStringify from 'remark-stringify';
6
6
  import { visit } from 'unist-util-visit';
7
- import { logWarning } from '../console/logging.js';
7
+ import { logger } from '../console/logger.js';
8
8
  import escapeHtmlInTextNodes from 'gt-remark';
9
9
  /**
10
10
  * Generates a slug from heading text
@@ -90,7 +90,7 @@ export function addExplicitAnchorIds(translatedContent, sourceHeadingMap, settin
90
90
  const translatedFile = translatedPath
91
91
  ? `translated file: ${translatedPath}`
92
92
  : 'translated file';
93
- logWarning(`Header count mismatch detected! ${sourceFile} has ${sourceHeadingMap.length} headers but ${translatedFile} has ${translatedHeadings.length} headers. ` +
93
+ logger.warn(`Header count mismatch detected! ${sourceFile} has ${sourceHeadingMap.length} headers but ${translatedFile} has ${translatedHeadings.length} headers. ` +
94
94
  `This likely means your source file was edited after translation was requested, causing a mismatch between ` +
95
95
  `the number of headers in your source file vs the translated file. Please re-translate this file to resolve the issue.`);
96
96
  }
@@ -1,4 +1,5 @@
1
- import { createSpinner, logErrorAndExit, logMessage, } from '../console/logging.js';
1
+ import { logErrorAndExit } from '../console/logging.js';
2
+ import { logger } from '../console/logger.js';
2
3
  import path from 'node:path';
3
4
  import fs from 'node:fs';
4
5
  import chalk from 'chalk';
@@ -10,8 +11,8 @@ export async function retrieveCredentials(settings, keyType) {
10
11
  await import('open').then((open) => open.default(urlToOpen, {
11
12
  wait: false,
12
13
  }));
13
- logMessage(`${chalk.dim(`If the browser window didn't open automatically, please open the following link:`)}\n\n${chalk.cyan(urlToOpen)}`);
14
- const spinner = createSpinner('dots');
14
+ logger.message(`${chalk.dim(`If the browser window didn't open automatically, please open the following link:`)}\n\n${chalk.cyan(urlToOpen)}`);
15
+ const spinner = logger.createSpinner('dots');
15
16
  spinner.start('Waiting for response from dashboard...');
16
17
  const credentials = await new Promise(async (resolve, reject) => {
17
18
  const interval = setInterval(async () => {
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { spawn } from 'child_process';
3
- import { logError, logInfo } from '../console/logging.js';
3
+ import { logger } from '../console/logger.js';
4
4
  export async function installPackage(packageName, packageManager, asDevDependency, cwd = process.cwd()) {
5
5
  return new Promise((resolve, reject) => {
6
6
  const command = packageManager.name;
@@ -19,8 +19,8 @@ export async function installPackage(packageName, packageManager, asDevDependenc
19
19
  });
20
20
  }
21
21
  childProcess.on('error', (error) => {
22
- logError(chalk.red(`Installation error: ${error.message}`));
23
- logInfo(`Please manually install ${packageName} with: ${packageManager.name} ${packageManager.installCommand} ${packageName}`);
22
+ logger.error(chalk.red(`Installation error: ${error.message}`));
23
+ logger.info(`Please manually install ${packageName} with: ${packageManager.name} ${packageManager.installCommand} ${packageName}`);
24
24
  reject(error);
25
25
  });
26
26
  childProcess.on('close', (code) => {
@@ -28,11 +28,11 @@ export async function installPackage(packageName, packageManager, asDevDependenc
28
28
  resolve();
29
29
  }
30
30
  else {
31
- logError(chalk.red(`Installation failed with exit code ${code}`));
31
+ logger.error(chalk.red(`Installation failed with exit code ${code}`));
32
32
  if (errorOutput) {
33
- logError(chalk.red(`Error details: ${errorOutput}`));
33
+ logger.error(chalk.red(`Error details: ${errorOutput}`));
34
34
  }
35
- logInfo(`Please manually install ${packageName} with: ${packageManager.name} ${packageManager.installCommand} ${packageName}`);
35
+ logger.info(`Please manually install ${packageName} with: ${packageManager.name} ${packageManager.installCommand} ${packageName}`);
36
36
  reject(new Error(`Process exited with code ${code}`));
37
37
  }
38
38
  });
@@ -56,8 +56,8 @@ export async function installPackageGlobal(packageName, version) {
56
56
  });
57
57
  }
58
58
  childProcess.on('error', (error) => {
59
- logError(chalk.red(`Installation error: ${error.message}`));
60
- logInfo(`Please manually install ${packageName} with: npm install -g ${packageName}`);
59
+ logger.error(chalk.red(`Installation error: ${error.message}`));
60
+ logger.info(`Please manually install ${packageName} with: npm install -g ${packageName}`);
61
61
  reject(error);
62
62
  });
63
63
  childProcess.on('close', (code) => {
@@ -65,11 +65,11 @@ export async function installPackageGlobal(packageName, version) {
65
65
  resolve();
66
66
  }
67
67
  else {
68
- logError(chalk.red(`Installation failed with exit code ${code}`));
68
+ logger.error(chalk.red(`Installation failed with exit code ${code}`));
69
69
  if (errorOutput) {
70
- logError(chalk.red(`Error details: ${errorOutput}`));
70
+ logger.error(chalk.red(`Error details: ${errorOutput}`));
71
71
  }
72
- logInfo(`Please manually install ${packageName} with: npm install -g ${packageName}`);
72
+ logger.info(`Please manually install ${packageName} with: npm install -g ${packageName}`);
73
73
  reject(new Error(`Process exited with code ${code}`));
74
74
  }
75
75
  });
@@ -1,8 +1,9 @@
1
- import { logError } from '../console/logging.js';
1
+ import { logger } from '../console/logger.js';
2
2
  import chalk from 'chalk';
3
3
  import path from 'node:path';
4
4
  import fs from 'node:fs';
5
5
  import { fromPackageRoot } from '../fs/getPackageResource.js';
6
+ import { exitSync } from '../console/logging.js';
6
7
  // search for package.json such that we can run init in non-js projects
7
8
  export async function searchForPackageJson(cwd = process.cwd()) {
8
9
  // Get the current working directory (where the CLI is being run)
@@ -48,8 +49,8 @@ export async function updatePackageJson(packageJson, cwd = process.cwd()) {
48
49
  await fs.promises.writeFile(path.join(cwd, 'package.json'), JSON.stringify(packageJson, null, 2));
49
50
  }
50
51
  catch (error) {
51
- logError(chalk.red('Error updating package.json: ' + String(error)));
52
- process.exit(1);
52
+ logger.error(chalk.red('Error updating package.json: ' + String(error)));
53
+ exitSync(1);
53
54
  }
54
55
  }
55
56
  // check if a package is installed in the package.json file
@@ -1,11 +1,12 @@
1
1
  import { WorkflowStep } from './Workflow.js';
2
- import { createSpinner, logError, logErrorAndExit, } from '../console/logging.js';
2
+ import { logErrorAndExit } from '../console/logging.js';
3
+ import { logger } from '../console/logger.js';
3
4
  import chalk from 'chalk';
4
5
  import { getCurrentBranch, getIncomingBranches, getCheckedOutBranches, } from '../git/branches.js';
5
6
  import { ApiError } from 'generaltranslation/errors';
6
7
  // Step 1: Resolve the current branch id & update API with branch information
7
8
  export class BranchStep extends WorkflowStep {
8
- spinner = createSpinner('dots');
9
+ spinner = logger.createSpinner('dots');
9
10
  branchData;
10
11
  settings;
11
12
  gt;
@@ -70,7 +71,7 @@ export class BranchStep extends WorkflowStep {
70
71
  }
71
72
  else {
72
73
  if (!current) {
73
- logErrorAndExit('Failed to determine the current branch. Please specify a custom branch or enable automatic branch detection.');
74
+ return logErrorAndExit('Failed to determine the current branch. Please specify a custom branch or enable automatic branch detection.');
74
75
  }
75
76
  const currentBranch = branchData.branches.find((b) => b.name === current.currentBranchName);
76
77
  if (!currentBranch) {
@@ -83,7 +84,7 @@ export class BranchStep extends WorkflowStep {
83
84
  }
84
85
  catch (error) {
85
86
  if (error instanceof ApiError && error.code === 403) {
86
- logError('Failed to create branch. To enable branching, please upgrade your plan.');
87
+ logger.error('Failed to create branch. To enable branching, please upgrade your plan.');
87
88
  // retry with default branch
88
89
  const createBranchResult = await this.gt.createBranch({
89
90
  branchName: 'main', // name doesn't matter for default branch
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { WorkflowStep } from './Workflow.js';
3
- import { createProgressBar, logError, logWarning } from '../console/logging.js';
3
+ import { logger } from '../console/logger.js';
4
4
  import { downloadFileBatch, } from '../api/downloadFileBatch.js';
5
5
  export class DownloadTranslationsStep extends WorkflowStep {
6
6
  gt;
@@ -12,7 +12,7 @@ export class DownloadTranslationsStep extends WorkflowStep {
12
12
  this.settings = settings;
13
13
  }
14
14
  async run({ fileTracker, resolveOutputPath, forceDownload, }) {
15
- this.spinner = createProgressBar(fileTracker.completed.size);
15
+ this.spinner = logger.createProgressBar(fileTracker.completed.size);
16
16
  this.spinner.start('Downloading files...');
17
17
  // Download ready files
18
18
  const success = await this.downloadFiles(fileTracker, resolveOutputPath, forceDownload);
@@ -73,7 +73,7 @@ export class DownloadTranslationsStep extends WorkflowStep {
73
73
  const batchResult = await this.downloadFilesWithRetry(fileTracker, batchFiles, forceDownload);
74
74
  this.spinner?.stop(chalk.green(`Downloaded ${batchResult.successful.length} files${batchResult.skipped.length > 0 ? `, skipped ${batchResult.skipped.length} files` : ''}`));
75
75
  if (batchResult.failed.length > 0) {
76
- logWarning(`Failed to download ${batchResult.failed.length} files: ${batchResult.failed.map((f) => f.inputPath).join('\n')}`);
76
+ logger.warn(`Failed to download ${batchResult.failed.length} files: ${batchResult.failed.map((f) => f.inputPath).join('\n')}`);
77
77
  }
78
78
  }
79
79
  else {
@@ -83,7 +83,7 @@ export class DownloadTranslationsStep extends WorkflowStep {
83
83
  }
84
84
  catch (error) {
85
85
  this.spinner?.stop(chalk.red('An error occurred while downloading translations'));
86
- logError(chalk.red('Error: ') + error);
86
+ logger.error(chalk.red('Error: ') + error);
87
87
  return false;
88
88
  }
89
89
  }
@@ -109,7 +109,7 @@ export class DownloadTranslationsStep extends WorkflowStep {
109
109
  }
110
110
  // Calculate exponential backoff delay
111
111
  const delay = initialDelay * Math.pow(2, retryCount);
112
- logError(chalk.yellow(`Retrying ${batchResult.failed.length} failed file(s) in ${delay}ms (attempt ${retryCount + 1}/${maxRetries})...`));
112
+ logger.error(chalk.yellow(`Retrying ${batchResult.failed.length} failed file(s) in ${delay}ms (attempt ${retryCount + 1}/${maxRetries})...`));
113
113
  // Wait before retrying
114
114
  await new Promise((resolve) => setTimeout(resolve, delay));
115
115
  remainingFiles = batchResult.failed;
@@ -1,11 +1,11 @@
1
1
  import { WorkflowStep } from './Workflow.js';
2
- import { createSpinner } from '../console/logging.js';
2
+ import { logger } from '../console/logger.js';
3
3
  import chalk from 'chalk';
4
4
  export class EnqueueStep extends WorkflowStep {
5
5
  gt;
6
6
  settings;
7
7
  force;
8
- spinner = createSpinner('dots');
8
+ spinner = logger.createSpinner('dots');
9
9
  result = null;
10
10
  constructor(gt, settings, force) {
11
11
  super();
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { WorkflowStep } from './Workflow.js';
3
- import { createProgressBar, logError } from '../console/logging.js';
3
+ import { logger } from '../console/logger.js';
4
4
  import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
5
5
  export class PollTranslationJobsStep extends WorkflowStep {
6
6
  gt;
@@ -12,7 +12,7 @@ export class PollTranslationJobsStep extends WorkflowStep {
12
12
  }
13
13
  async run({ fileTracker, fileQueryData, jobData, timeoutDuration, forceRetranslation, }) {
14
14
  const startTime = Date.now();
15
- this.spinner = createProgressBar(fileQueryData.length);
15
+ this.spinner = logger.createProgressBar(fileQueryData.length);
16
16
  const spinnerMessage = forceRetranslation
17
17
  ? 'Waiting for retranslation...'
18
18
  : 'Waiting for translation...';
@@ -144,7 +144,7 @@ export class PollTranslationJobsStep extends WorkflowStep {
144
144
  }
145
145
  }
146
146
  catch (error) {
147
- logError(chalk.red('Error checking job status: ') + error);
147
+ logger.error(chalk.red('Error checking job status: ') + error);
148
148
  }
149
149
  }, 5000);
150
150
  }, msUntilNextInterval);
@@ -1,11 +1,11 @@
1
1
  import { WorkflowStep } from './Workflow.js';
2
- import { createSpinner } from '../console/logging.js';
2
+ import { logger } from '../console/logger.js';
3
3
  import chalk from 'chalk';
4
4
  export class SetupStep extends WorkflowStep {
5
5
  gt;
6
6
  settings;
7
7
  timeoutMs;
8
- spinner = createSpinner('dots');
8
+ spinner = logger.createSpinner('dots');
9
9
  setupJobId = null;
10
10
  files = null;
11
11
  completed = false;