gt 2.14.66 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/api/downloadFileBatch.js +28 -1
  3. package/dist/api/downloadFileBatch.js.map +1 -1
  4. package/dist/api/saveLocalEdits.js +1 -3
  5. package/dist/api/saveLocalEdits.js.map +1 -1
  6. package/dist/cli/base.js +6 -0
  7. package/dist/cli/base.js.map +1 -1
  8. package/dist/cli/commands/download.js +2 -1
  9. package/dist/cli/commands/download.js.map +1 -1
  10. package/dist/cli/commands/upload.js +5 -3
  11. package/dist/cli/commands/upload.js.map +1 -1
  12. package/dist/cli/inline.js +1 -3
  13. package/dist/cli/inline.js.map +1 -1
  14. package/dist/console/index.d.ts +3 -0
  15. package/dist/console/index.js +4 -1
  16. package/dist/console/index.js.map +1 -1
  17. package/dist/console/logger.d.ts +13 -0
  18. package/dist/console/logger.js +35 -8
  19. package/dist/console/logger.js.map +1 -1
  20. package/dist/console/logging.js +4 -2
  21. package/dist/console/logging.js.map +1 -1
  22. package/dist/formats/files/aggregateFiles.js +32 -2
  23. package/dist/formats/files/aggregateFiles.js.map +1 -1
  24. package/dist/formats/files/collectFonts.d.ts +7 -0
  25. package/dist/formats/files/collectFonts.js +30 -0
  26. package/dist/formats/files/collectFonts.js.map +1 -0
  27. package/dist/formats/files/detectLottieExpressions.d.ts +8 -0
  28. package/dist/formats/files/detectLottieExpressions.js +42 -0
  29. package/dist/formats/files/detectLottieExpressions.js.map +1 -0
  30. package/dist/formats/files/supportedFiles.d.ts +2 -1
  31. package/dist/formats/files/supportedFiles.js +4 -2
  32. package/dist/formats/files/supportedFiles.js.map +1 -1
  33. package/dist/formats/files/transformFormat.d.ts +2 -0
  34. package/dist/formats/files/transformFormat.js +6 -3
  35. package/dist/formats/files/transformFormat.js.map +1 -1
  36. package/dist/fs/findFilepath.d.ts +7 -0
  37. package/dist/fs/findFilepath.js +11 -1
  38. package/dist/fs/findFilepath.js.map +1 -1
  39. package/dist/generated/version.d.ts +1 -1
  40. package/dist/generated/version.js +1 -1
  41. package/dist/generated/version.js.map +1 -1
  42. package/dist/types/index.d.ts +5 -0
  43. package/dist/workflows/download.js +3 -9
  44. package/dist/workflows/download.js.map +1 -1
  45. package/dist/workflows/enqueue.js +2 -2
  46. package/dist/workflows/enqueue.js.map +1 -1
  47. package/dist/workflows/publish.js +1 -3
  48. package/dist/workflows/publish.js.map +1 -1
  49. package/dist/workflows/setupProject.js +0 -3
  50. package/dist/workflows/setupProject.js.map +1 -1
  51. package/dist/workflows/stage.js +5 -13
  52. package/dist/workflows/stage.js.map +1 -1
  53. package/dist/workflows/steps/BranchStep.d.ts +1 -3
  54. package/dist/workflows/steps/BranchStep.js +1 -4
  55. package/dist/workflows/steps/BranchStep.js.map +1 -1
  56. package/dist/workflows/steps/DownloadStep.d.ts +1 -3
  57. package/dist/workflows/steps/DownloadStep.js +1 -4
  58. package/dist/workflows/steps/DownloadStep.js.map +1 -1
  59. package/dist/workflows/steps/EnqueueStep.d.ts +1 -5
  60. package/dist/workflows/steps/EnqueueStep.js +9 -19
  61. package/dist/workflows/steps/EnqueueStep.js.map +1 -1
  62. package/dist/workflows/steps/PollJobsStep.d.ts +1 -3
  63. package/dist/workflows/steps/PollJobsStep.js +1 -4
  64. package/dist/workflows/steps/PollJobsStep.js.map +1 -1
  65. package/dist/workflows/steps/PublishStep.d.ts +1 -3
  66. package/dist/workflows/steps/PublishStep.js +1 -4
  67. package/dist/workflows/steps/PublishStep.js.map +1 -1
  68. package/dist/workflows/steps/SetupStep.d.ts +1 -6
  69. package/dist/workflows/steps/SetupStep.js +14 -41
  70. package/dist/workflows/steps/SetupStep.js.map +1 -1
  71. package/dist/workflows/steps/TagStep.d.ts +1 -4
  72. package/dist/workflows/steps/TagStep.js +4 -9
  73. package/dist/workflows/steps/TagStep.js.map +1 -1
  74. package/dist/workflows/steps/UploadSourcesStep.d.ts +1 -7
  75. package/dist/workflows/steps/UploadSourcesStep.js +4 -8
  76. package/dist/workflows/steps/UploadSourcesStep.js.map +1 -1
  77. package/dist/workflows/steps/UploadTranslationsStep.d.ts +1 -4
  78. package/dist/workflows/steps/UploadTranslationsStep.js +6 -11
  79. package/dist/workflows/steps/UploadTranslationsStep.js.map +1 -1
  80. package/dist/workflows/steps/UserEditDiffsStep.d.ts +1 -5
  81. package/dist/workflows/steps/UserEditDiffsStep.js +3 -11
  82. package/dist/workflows/steps/UserEditDiffsStep.js.map +1 -1
  83. package/dist/workflows/upload.js +3 -6
  84. package/dist/workflows/upload.js.map +1 -1
  85. package/dist/workflows/utils/syncFonts.d.ts +9 -0
  86. package/dist/workflows/utils/syncFonts.js +25 -0
  87. package/dist/workflows/utils/syncFonts.js.map +1 -0
  88. package/package.json +7 -6
  89. package/dist/workflows/steps/WorkflowStep.d.ts +0 -4
  90. package/dist/workflows/steps/WorkflowStep.js +0 -6
  91. package/dist/workflows/steps/WorkflowStep.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"inline.js","names":[],"sources":["../../src/cli/inline.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { BaseCLI } from './base.js';\nimport { SupportedLibraries, TranslateFlags, Options } from '../types/index.js';\nimport {\n attachInlineTranslateFlags,\n attachTranslateFlags,\n attachValidateFlags,\n} from './flags.js';\nimport { displayHeader, exitSync } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { intro } from '@clack/prompts';\nimport chalk from 'chalk';\nimport { resolveLocaleFiles } from '../fs/config/parseFilesConfig.js';\nimport { noFilesError } from '../console/index.js';\nimport { saveJSON } from '../fs/saveJSON.js';\nimport loadJSON from '../fs/loadJSON.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport { aggregateInlineTranslations } from '../translation/stage.js';\nimport { validateProject } from '../translation/validate.js';\nimport { Libraries, InlineLibrary } from '../types/libraries.js';\n\n/**\n * Stand in for a CLI tool that does any sort of inline content translations\n */\nexport class InlineCLI extends BaseCLI {\n constructor(\n command: Command,\n library: InlineLibrary,\n additionalModules?: SupportedLibraries[]\n ) {\n super(command, library, additionalModules);\n }\n public init() {\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupGenerateSourceCommand();\n this.setupValidateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n\n protected setupStageCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('translate')\n .description(\n 'Scans the project for a dictionary and inline translations and sends the updates to the General Translation API for translation.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader('Translating project...');\n await this.handleTranslate(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupValidateCommand(): void {\n attachValidateFlags(\n this.program\n .command('validate [files...]')\n .description(\n 'Scans the project for a dictionary and/or inline content and validates the project for errors.'\n )\n ).action(async (files: string[], options: Options) => {\n // intro here since we don't want to show the ascii title\n intro(chalk.cyan('Validating project...'));\n await this.handleValidate(options, files);\n logger.endCommand('Done!');\n });\n }\n\n protected setupGenerateSourceCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('generate')\n .description(\n 'Generate a translation file for the source locale. This command should be used if you are handling your own translations.'\n )\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Generating source templates...');\n await this.handleGenerateSourceCommand(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected async handleGenerateSourceCommand(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const updates = await aggregateInlineTranslations(\n initOptions,\n settings,\n fallbackToGtReact(this.library)\n );\n\n // Convert updates to the proper data format\n const newData: Record<string, unknown> = {};\n for (const update of updates) {\n const { source, metadata } = update;\n const { hash } = metadata;\n if (hash) {\n newData[hash] = source;\n }\n }\n\n // Save source file if files.json is provided\n if (settings.files && settings.files.placeholderPaths.gt) {\n const translationFiles = resolveLocaleFiles(\n settings.files.placeholderPaths,\n settings.defaultLocale\n );\n if (!translationFiles.gt) {\n logger.error(noFilesError);\n exitSync(1);\n }\n await saveJSON(translationFiles.gt, newData);\n logger.step('Source file saved successfully!');\n // Also save translations (after merging with existing translations)\n for (const locale of settings.locales) {\n const translationsFile = resolveLocaleFiles(\n settings.files.placeholderPaths,\n locale\n );\n\n if (!translationsFile.gt) {\n continue;\n }\n const existingTranslations = loadJSON(translationsFile.gt);\n const mergedTranslations = {\n ...newData,\n ...existingTranslations,\n };\n // Filter out keys that don't exist in newData\n const filteredTranslations = Object.fromEntries(\n Object.entries(mergedTranslations).filter(([key]) => newData[key])\n );\n await saveJSON(translationsFile.gt, filteredTranslations);\n }\n logger.step('Merged translations successfully!');\n }\n }\n\n protected async handleValidate(\n initOptions: Options,\n files?: string[]\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // First run the base class's handleTranslate method\n const options = { ...initOptions, ...settings };\n\n // Fallback to gt-react\n const pkg = fallbackToGtReact(this.library);\n\n if (files && files.length > 0) {\n // Validate specific files using createInlineUpdates\n await validateProject(options, pkg, files);\n } else {\n // Validate whole project as before\n await validateProject(options, pkg);\n }\n }\n}\n\nfunction fallbackToGtReact(library: SupportedLibraries): InlineLibrary {\n return [\n Libraries.GT_NEXT,\n Libraries.GT_NODE,\n Libraries.GT_REACT_NATIVE,\n Libraries.GT_TANSTACK_START,\n Libraries.GT_FLASK,\n Libraries.GT_FASTAPI,\n ].includes(library as Libraries)\n ? (library as\n | typeof Libraries.GT_NEXT\n | typeof Libraries.GT_NODE\n | typeof Libraries.GT_REACT_NATIVE\n | typeof Libraries.GT_TANSTACK_START\n | typeof Libraries.GT_FLASK\n | typeof Libraries.GT_FASTAPI)\n : Libraries.GT_REACT;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inline.js","names":[],"sources":["../../src/cli/inline.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { BaseCLI } from './base.js';\nimport { SupportedLibraries, TranslateFlags, Options } from '../types/index.js';\nimport {\n attachInlineTranslateFlags,\n attachTranslateFlags,\n attachValidateFlags,\n} from './flags.js';\nimport { displayHeader, exitSync } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { resolveLocaleFiles } from '../fs/config/parseFilesConfig.js';\nimport { noFilesError } from '../console/index.js';\nimport { saveJSON } from '../fs/saveJSON.js';\nimport loadJSON from '../fs/loadJSON.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport { aggregateInlineTranslations } from '../translation/stage.js';\nimport { validateProject } from '../translation/validate.js';\nimport { Libraries, InlineLibrary } from '../types/libraries.js';\n\n/**\n * Stand in for a CLI tool that does any sort of inline content translations\n */\nexport class InlineCLI extends BaseCLI {\n constructor(\n command: Command,\n library: InlineLibrary,\n additionalModules?: SupportedLibraries[]\n ) {\n super(command, library, additionalModules);\n }\n public init() {\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupGenerateSourceCommand();\n this.setupValidateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n\n protected setupStageCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('translate')\n .description(\n 'Scans the project for a dictionary and inline translations and sends the updates to the General Translation API for translation.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader('Translating project...');\n await this.handleTranslate(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupValidateCommand(): void {\n attachValidateFlags(\n this.program\n .command('validate [files...]')\n .description(\n 'Scans the project for a dictionary and/or inline content and validates the project for errors.'\n )\n ).action(async (files: string[], options: Options) => {\n // startCommand here since we don't want to show the ascii title; it\n // renders the same intro while honoring --quiet.\n logger.startCommand('Validating project...');\n await this.handleValidate(options, files);\n logger.endCommand('Done!');\n });\n }\n\n protected setupGenerateSourceCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('generate')\n .description(\n 'Generate a translation file for the source locale. This command should be used if you are handling your own translations.'\n )\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Generating source templates...');\n await this.handleGenerateSourceCommand(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected async handleGenerateSourceCommand(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const updates = await aggregateInlineTranslations(\n initOptions,\n settings,\n fallbackToGtReact(this.library)\n );\n\n // Convert updates to the proper data format\n const newData: Record<string, unknown> = {};\n for (const update of updates) {\n const { source, metadata } = update;\n const { hash } = metadata;\n if (hash) {\n newData[hash] = source;\n }\n }\n\n // Save source file if files.json is provided\n if (settings.files && settings.files.placeholderPaths.gt) {\n const translationFiles = resolveLocaleFiles(\n settings.files.placeholderPaths,\n settings.defaultLocale\n );\n if (!translationFiles.gt) {\n logger.error(noFilesError);\n exitSync(1);\n }\n await saveJSON(translationFiles.gt, newData);\n logger.step('Source file saved successfully!');\n // Also save translations (after merging with existing translations)\n for (const locale of settings.locales) {\n const translationsFile = resolveLocaleFiles(\n settings.files.placeholderPaths,\n locale\n );\n\n if (!translationsFile.gt) {\n continue;\n }\n const existingTranslations = loadJSON(translationsFile.gt);\n const mergedTranslations = {\n ...newData,\n ...existingTranslations,\n };\n // Filter out keys that don't exist in newData\n const filteredTranslations = Object.fromEntries(\n Object.entries(mergedTranslations).filter(([key]) => newData[key])\n );\n await saveJSON(translationsFile.gt, filteredTranslations);\n }\n logger.step('Merged translations successfully!');\n }\n }\n\n protected async handleValidate(\n initOptions: Options,\n files?: string[]\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // First run the base class's handleTranslate method\n const options = { ...initOptions, ...settings };\n\n // Fallback to gt-react\n const pkg = fallbackToGtReact(this.library);\n\n if (files && files.length > 0) {\n // Validate specific files using createInlineUpdates\n await validateProject(options, pkg, files);\n } else {\n // Validate whole project as before\n await validateProject(options, pkg);\n }\n }\n}\n\nfunction fallbackToGtReact(library: SupportedLibraries): InlineLibrary {\n return [\n Libraries.GT_NEXT,\n Libraries.GT_NODE,\n Libraries.GT_REACT_NATIVE,\n Libraries.GT_TANSTACK_START,\n Libraries.GT_FLASK,\n Libraries.GT_FASTAPI,\n ].includes(library as Libraries)\n ? (library as\n | typeof Libraries.GT_NEXT\n | typeof Libraries.GT_NODE\n | typeof Libraries.GT_REACT_NATIVE\n | typeof Libraries.GT_TANSTACK_START\n | typeof Libraries.GT_FLASK\n | typeof Libraries.GT_FASTAPI)\n : Libraries.GT_REACT;\n}\n"],"mappings":"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"}
@@ -40,6 +40,9 @@ export declare const noSourceFileError = "No source translation file was found.
40
40
  export declare const noApiKeyError = "No API key was found. Pass --api-key or set the GT_API_KEY environment variable.";
41
41
  export declare const devApiKeyError = "Development API keys cannot be used with the General Translation API. Use a production API key instead.\nGenerate a production API key with: npx gt auth -t production";
42
42
  export declare const noProjectIdError = "No project ID was found. Pass --project-id, add projectId to gt.config.json, or set the GT_PROJECT_ID environment variable.";
43
+ export declare const noVersionIdError = "No version ID was found. Pass --version-id or add _versionId to gt.config.json.";
43
44
  export declare const invalidConfigurationError = "The files configuration cannot be used for this operation. Provide a valid download configuration or set --publish true to upload translations to the CDN.";
45
+ export declare const lottieTranslateError = "Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\n 1. Stage the files for translation: npx gt stage\n 2. Fetch the finished translations: npx gt download\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.";
44
46
  export declare const branchResolutionError = "The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.";
47
+ export declare const lottieExpressionsError: (files: string[]) => string;
45
48
  export declare const withOriginalError: (message: string, error: unknown) => string;
@@ -53,10 +53,13 @@ const noSourceFileError = `No source translation file was found. Check your tran
53
53
  const noApiKeyError = `No API key was found. Pass --api-key or set the GT_API_KEY environment variable.`;
54
54
  const devApiKeyError = `Development API keys cannot be used with the General Translation API. Use a production API key instead.\nGenerate a production API key with: npx gt auth -t production`;
55
55
  const noProjectIdError = `No project ID was found. Pass --project-id, add projectId to gt.config.json, or set the GT_PROJECT_ID environment variable.`;
56
+ const noVersionIdError = `No version ID was found. Pass --version-id or add _versionId to gt.config.json.`;
56
57
  const invalidConfigurationError = `The files configuration cannot be used for this operation. Provide a valid download configuration or set --publish true to upload translations to the CDN.`;
58
+ const lottieTranslateError = `Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\n 1. Stage the files for translation: npx gt stage\n 2. Fetch the finished translations: npx gt download\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.`;
57
59
  const branchResolutionError = `The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.`;
60
+ const lottieExpressionsError = (files) => `The following Lottie file(s) use After Effects expressions, which contain executable code and are not supported yet:\n${files.map((file) => ` - ${file}`).join("\n")}\nRe-export the animation with expressions baked into keyframes (or removed), then try again.`;
58
61
  const withOriginalError = (message, error) => error != null ? `${message} Original error: ${String(error)}` : message;
59
62
  //#endregion
60
- export { branchResolutionError, devApiKeyError, invalidConfigurationError, noApiKeyError, noDefaultLocaleError, noFilesError, noLocalesError, noProjectIdError, noSourceFileError, warnApiKeyInConfigSync, warnAsyncUseGT, warnAutoderiveNoResultsSync, warnDataAttrOnBranch, warnDeprecatedTSugarPropsSync, warnDeriveCircularSpreadSync, warnDeriveDestructuringSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, warnDeriveNonConstVariableSync, warnDeriveOptionalChainingSync, warnDeriveUnresolvableValueSync, warnDuplicateFunctionDefinitionSync, warnFailedToConstructJsxTreeSync, warnFunctionNotFoundSync, warnHasUnwrappedExpressionSync, warnInvalidDeclareVarNameSync, warnInvalidDeriveInitSync, warnInvalidFormatSync, warnInvalidIcuSync, warnInvalidMaxCharsSync, warnInvalidRequiresReviewSync, warnInvalidReturnSync, warnMissingReturnSync, warnNestedInternalTComponent, warnNestedTComponent, warnNonStaticExpressionSync, warnNonStringSync, warnRecursiveFunctionCallSync, warnSyncGetGT, warnTemplateLiteralSync, warnTernarySync, warnUnresolvedImportSync, warnVariablePropSync, withLocation, withOriginalError };
63
+ export { branchResolutionError, devApiKeyError, invalidConfigurationError, lottieExpressionsError, lottieTranslateError, noApiKeyError, noDefaultLocaleError, noFilesError, noLocalesError, noProjectIdError, noSourceFileError, noVersionIdError, warnApiKeyInConfigSync, warnAsyncUseGT, warnAutoderiveNoResultsSync, warnDataAttrOnBranch, warnDeprecatedTSugarPropsSync, warnDeriveCircularSpreadSync, warnDeriveDestructuringSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, warnDeriveNonConstVariableSync, warnDeriveOptionalChainingSync, warnDeriveUnresolvableValueSync, warnDuplicateFunctionDefinitionSync, warnFailedToConstructJsxTreeSync, warnFunctionNotFoundSync, warnHasUnwrappedExpressionSync, warnInvalidDeclareVarNameSync, warnInvalidDeriveInitSync, warnInvalidFormatSync, warnInvalidIcuSync, warnInvalidMaxCharsSync, warnInvalidRequiresReviewSync, warnInvalidReturnSync, warnMissingReturnSync, warnNestedInternalTComponent, warnNestedTComponent, warnNonStaticExpressionSync, warnNonStringSync, warnRecursiveFunctionCallSync, warnSyncGetGT, warnTemplateLiteralSync, warnTernarySync, warnUnresolvedImportSync, warnVariablePropSync, withLocation, withOriginalError };
61
64
 
62
65
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/console/index.ts"],"sourcesContent":["import { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { BRANCH_COMPONENT } from '../react/jsx/utils/constants.js';\nimport {\n colorizeFilepath,\n colorizeComponent,\n colorizeIdString,\n colorizeContent,\n colorizeLine,\n colorizeFunctionName,\n} from './colors.js';\nimport { formatCodeClamp } from './formatting.js';\n\nconst withWillErrorInNextVersion = (message: string): string =>\n `${message} (This will become an error in the next major version of the CLI.)`;\n\n// Derive function related errors\nconst withDeriveComponentError = (message: string): string =>\n `<Derive> rules violation: ${message}`;\n\nconst withDeriveFunctionError = (message: string): string =>\n `derive() rules violation: ${message}`;\n// Synchronous wrappers for backward compatibility\nexport const warnApiKeyInConfigSync = (optionsFilepath: string): string =>\n `${colorizeFilepath(\n optionsFilepath\n )}: Your API key is exposed! Remove it from the file and include it as an environment variable.`;\n\nexport const warnVariablePropSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component has dynamic attribute ${colorizeIdString(attrName)} with value: ${colorizeContent(\n value\n )}. Change ${colorizeIdString(attrName)} to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidReturnSync = (\n file: string,\n functionName: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Function ${colorizeFunctionName(functionName)} does not return a derivable (statically analyzable) expression. ${colorizeFunctionName(functionName)} must return either (1) a derivable string literal, (2) another derivable function invocation, (3) derivable JSX content, or (4) a ternary expression. Instead got:\\n${colorizeContent(expression)}`\n ),\n location\n );\n\n// TODO: this is temporary until we handle implicit returns\nexport const warnMissingReturnSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is wrapped in ${colorizeComponent('<Derive>')} tags but does not have an explicit return statement. Derivable functions must have an explicit return statement.`,\n location\n );\n\nexport const warnHasUnwrappedExpressionSync = (\n file: string,\n unwrappedExpressions: string[],\n id?: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component${\n id ? ` with id ${colorizeIdString(id)}` : ''\n } has children that could change at runtime. Use a variable component like ${colorizeComponent(\n '<Var>'\n )} to ensure this content is translated.\\n${colorizeContent(\n unwrappedExpressions.join('\\n')\n )}`,\n location\n );\n\nexport const warnFailedToConstructJsxTreeSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Failed to construct JsxTree! Call expression is not a valid createElement call: ${colorizeContent(code)}`,\n location\n );\n\nexport const warnNestedTComponent = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found nested <T> component. <T> components cannot be directly nested.`,\n location\n );\n\nexport const warnNestedInternalTComponent = (\n file: string,\n location?: string\n): string =>\n withLocation(\n file,\n `DEBUG: Found nested <GtInternalTranslateJsx> component. <GtInternalTranslateJsx> components cannot be directly nested.`,\n location\n );\n\nexport const warnNonStaticExpressionSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-static expression for attribute ${colorizeIdString(\n attrName\n )}: ${colorizeContent(value)}. Change \"${colorizeIdString(attrName)}\" to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidMaxCharsSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid maxChars value: ${colorizeContent(value)}. maxChars must be a numeric literal, e.g. maxChars={10}, to ensure this content is translated.`,\n location\n );\n\nexport const warnDeprecatedTSugarPropsSync = (locations: string[]): string =>\n createDiagnosticMessage({\n whatHappened: `Found ${locations.length} deprecated ${colorizeIdString(\n '$'\n )}-prefixed prop${locations.length === 1 ? '' : 's'} on ${colorizeComponent(\n '<T>'\n )} components`,\n fix: `Use the unprefixed forms instead (${colorizeIdString(\n 'context'\n )}, ${colorizeIdString('id')}, ${colorizeIdString('maxChars')}, ${colorizeIdString(\n 'requiresReview'\n )}); support for the ${colorizeIdString('$')}-prefixed forms will be removed in the next major version`,\n }) +\n '\\n' +\n locations.map((location) => ` ${colorizeLine(location)}`).join('\\n');\n\nexport const warnInvalidFormatSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid $format value: ${colorizeContent(value)}. Must be one of: 'ICU', 'STRING', 'I18NEXT'.`,\n location\n );\n\nexport const warnInvalidRequiresReviewSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid requiresReview value: ${colorizeContent(value)}. Must be a boolean literal (true or false) — strings and dynamic expressions are not allowed.`,\n location\n );\n\nexport const warnInvalidIcuSync = (\n file: string,\n value: string,\n error: string,\n location?: string\n): string =>\n withWillErrorInNextVersion(\n withLocation(\n file,\n `Found invalid ICU string: ${colorizeContent(value)}. Change the value to a valid ICU to ensure this content is translated. Error message: ${error}.`,\n location\n )\n );\n\nexport const warnTemplateLiteralSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found template literal with quasis (${colorizeContent(value)}). Change the template literal to a string to ensure this content is translated.`,\n location\n );\n\nexport const warnNonStringSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-string literal (${colorizeContent(value)}). Change the value to a string literal to ensure this content is translated.`,\n location\n );\n\nexport const warnAsyncUseGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found useGT() in an async function. Use getGT() instead, or make the function synchronous.`,\n location\n );\n\nexport const warnSyncGetGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found getGT() in a synchronous function. Use useGT() instead, or make the function async.`,\n location\n );\n\nexport const warnTernarySync = (file: string, location?: string): string =>\n withLocation(\n file,\n 'Found ternary expression. A Branch component may be more appropriate here.',\n location\n );\n\nexport const withLocation = (\n file: string,\n message: string,\n location?: string\n): string =>\n `${colorizeFilepath(file)}${location ? ` (${colorizeLine(location)})` : ''}: ${message}`;\n\nexport const warnFunctionNotFoundSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} definition could not be resolved. This might affect translation resolution for this ${colorizeComponent('<T>')} component.`,\n location\n );\n\nexport const warnInvalidDeclareVarNameSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid declareVar() $name tag. Must be a derivable (statically analyzable) expression. Received: ${colorizeContent(value)}.`,\n location\n );\n\nexport const warnDuplicateFunctionDefinitionSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is defined multiple times. Only the first definition will be used.`,\n location\n );\n\nexport const warnInvalidDeriveInitSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `The definition for ${colorizeFunctionName(functionName)} could not be resolved. When using arrow syntax to define a derivable (statically analyzable) function, the right hand side or the assignment MUST only contain the arrow function itself and no other expressions.\nExample: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = () => { ... }`)}\nInvalid: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = [() => { ... }][0]`)}`\n ),\n location\n );\n\nexport const warnDataAttrOnBranch = (\n file: string,\n attrName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent(`<${BRANCH_COMPONENT}>`)} component ignores attributes prefixed with ${colorizeIdString('\"data-\"')}. Found ${colorizeIdString(attrName)}. Remove it or use a different attribute name.`,\n location\n );\n\nexport const warnRecursiveFunctionCallSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Recursive function call detected: ${colorizeFunctionName(functionName)}. A derivable (statically analyzable) function cannot use recursive calls to construct its result.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNotWrappedSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. This call is not wrapped in derive(). Ensure the function is properly wrapped with derive() and does not have circular import dependencies.`\n ),\n location\n );\n\nexport const warnDeriveNonConstVariableSync = (\n file: string,\n varName: string,\n kind: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} is declared with '${kind}' but only 'const' declarations can be resolved statically. Change it to 'const'.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNoResultsSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. derive() can only receive function invocations and cannot use undefined values or looped calls to construct its result.`\n ),\n location\n );\n\nexport const warnAutoderiveNoResultsSync = (\n file: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Autoderive could not resolve ${colorizeFunctionName(formatCodeClamp(expression))}. Only function calls with statically determinable return values can be used directly in t(). Consider wrapping with derive() for explicit derivation, or use an interpolation variable instead.`,\n location\n );\n\nexport const warnDeriveUnresolvableValueSync = (\n file: string,\n key: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Object property ${colorizeFunctionName(formatCodeClamp(key))} could not be resolved to a static string value. Only string literals, template literals, conditionals, and function calls returning strings are supported.`\n ),\n location\n );\n\nexport const warnDeriveCircularSpreadSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Circular spread detected involving ${colorizeFunctionName(varName)}. Spread references that form a cycle cannot be resolved statically.`\n ),\n location\n );\n\nexport const warnDeriveDestructuringSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} uses destructuring syntax, which is not yet supported in derive(). Assign the value to a const variable directly instead.`\n ),\n location\n );\n\nexport const warnDeriveOptionalChainingSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Optional chaining (${colorizeFunctionName(formatCodeClamp(code))}) is not supported in derive(). Optional chaining implies the value could be undefined, which cannot be resolved statically. Use a non-optional access instead.`\n ),\n location\n );\n\nexport const warnUnresolvedImportSync = (\n file: string,\n functionName: string,\n importPath: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Could not resolve import ${colorizeFunctionName(importPath)} for function ${colorizeFunctionName(functionName)}. Translation strings inside this function will not be extracted.`,\n location\n );\n\n// Re-export error messages\nexport const noLocalesError = `No target locales were found. Add locales to gt.config.json or pass them with the --locales flag.`;\nexport const noDefaultLocaleError = `No default locale was found. Add defaultLocale to gt.config.json or pass it with --default-locale.`;\nexport const noFilesError = `The files configuration is missing or invalid. Check the files section in gt.config.json and try again.`;\nexport const noSourceFileError = `No source translation file was found. Check your translations directory and default locale configuration.`;\nexport const noApiKeyError = `No API key was found. Pass --api-key or set the GT_API_KEY environment variable.`;\nexport const devApiKeyError = `Development API keys cannot be used with the General Translation API. Use a production API key instead.\\nGenerate a production API key with: npx gt auth -t production`;\nexport const noProjectIdError = `No project ID was found. Pass --project-id, add projectId to gt.config.json, or set the GT_PROJECT_ID environment variable.`;\nexport const invalidConfigurationError = `The files configuration cannot be used for this operation. Provide a valid download configuration or set --publish true to upload translations to the CDN.`;\nexport const branchResolutionError = `The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.`;\n\nexport const withOriginalError = (message: string, error: unknown): string =>\n error != null ? `${message} Original error: ${String(error)}` : message;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/console/index.ts"],"sourcesContent":["import { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { BRANCH_COMPONENT } from '../react/jsx/utils/constants.js';\nimport {\n colorizeFilepath,\n colorizeComponent,\n colorizeIdString,\n colorizeContent,\n colorizeLine,\n colorizeFunctionName,\n} from './colors.js';\nimport { formatCodeClamp } from './formatting.js';\n\nconst withWillErrorInNextVersion = (message: string): string =>\n `${message} (This will become an error in the next major version of the CLI.)`;\n\n// Derive function related errors\nconst withDeriveComponentError = (message: string): string =>\n `<Derive> rules violation: ${message}`;\n\nconst withDeriveFunctionError = (message: string): string =>\n `derive() rules violation: ${message}`;\n// Synchronous wrappers for backward compatibility\nexport const warnApiKeyInConfigSync = (optionsFilepath: string): string =>\n `${colorizeFilepath(\n optionsFilepath\n )}: Your API key is exposed! Remove it from the file and include it as an environment variable.`;\n\nexport const warnVariablePropSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component has dynamic attribute ${colorizeIdString(attrName)} with value: ${colorizeContent(\n value\n )}. Change ${colorizeIdString(attrName)} to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidReturnSync = (\n file: string,\n functionName: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Function ${colorizeFunctionName(functionName)} does not return a derivable (statically analyzable) expression. ${colorizeFunctionName(functionName)} must return either (1) a derivable string literal, (2) another derivable function invocation, (3) derivable JSX content, or (4) a ternary expression. Instead got:\\n${colorizeContent(expression)}`\n ),\n location\n );\n\n// TODO: this is temporary until we handle implicit returns\nexport const warnMissingReturnSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is wrapped in ${colorizeComponent('<Derive>')} tags but does not have an explicit return statement. Derivable functions must have an explicit return statement.`,\n location\n );\n\nexport const warnHasUnwrappedExpressionSync = (\n file: string,\n unwrappedExpressions: string[],\n id?: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component${\n id ? ` with id ${colorizeIdString(id)}` : ''\n } has children that could change at runtime. Use a variable component like ${colorizeComponent(\n '<Var>'\n )} to ensure this content is translated.\\n${colorizeContent(\n unwrappedExpressions.join('\\n')\n )}`,\n location\n );\n\nexport const warnFailedToConstructJsxTreeSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Failed to construct JsxTree! Call expression is not a valid createElement call: ${colorizeContent(code)}`,\n location\n );\n\nexport const warnNestedTComponent = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found nested <T> component. <T> components cannot be directly nested.`,\n location\n );\n\nexport const warnNestedInternalTComponent = (\n file: string,\n location?: string\n): string =>\n withLocation(\n file,\n `DEBUG: Found nested <GtInternalTranslateJsx> component. <GtInternalTranslateJsx> components cannot be directly nested.`,\n location\n );\n\nexport const warnNonStaticExpressionSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-static expression for attribute ${colorizeIdString(\n attrName\n )}: ${colorizeContent(value)}. Change \"${colorizeIdString(attrName)}\" to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidMaxCharsSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid maxChars value: ${colorizeContent(value)}. maxChars must be a numeric literal, e.g. maxChars={10}, to ensure this content is translated.`,\n location\n );\n\nexport const warnDeprecatedTSugarPropsSync = (locations: string[]): string =>\n createDiagnosticMessage({\n whatHappened: `Found ${locations.length} deprecated ${colorizeIdString(\n '$'\n )}-prefixed prop${locations.length === 1 ? '' : 's'} on ${colorizeComponent(\n '<T>'\n )} components`,\n fix: `Use the unprefixed forms instead (${colorizeIdString(\n 'context'\n )}, ${colorizeIdString('id')}, ${colorizeIdString('maxChars')}, ${colorizeIdString(\n 'requiresReview'\n )}); support for the ${colorizeIdString('$')}-prefixed forms will be removed in the next major version`,\n }) +\n '\\n' +\n locations.map((location) => ` ${colorizeLine(location)}`).join('\\n');\n\nexport const warnInvalidFormatSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid $format value: ${colorizeContent(value)}. Must be one of: 'ICU', 'STRING', 'I18NEXT'.`,\n location\n );\n\nexport const warnInvalidRequiresReviewSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid requiresReview value: ${colorizeContent(value)}. Must be a boolean literal (true or false) — strings and dynamic expressions are not allowed.`,\n location\n );\n\nexport const warnInvalidIcuSync = (\n file: string,\n value: string,\n error: string,\n location?: string\n): string =>\n withWillErrorInNextVersion(\n withLocation(\n file,\n `Found invalid ICU string: ${colorizeContent(value)}. Change the value to a valid ICU to ensure this content is translated. Error message: ${error}.`,\n location\n )\n );\n\nexport const warnTemplateLiteralSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found template literal with quasis (${colorizeContent(value)}). Change the template literal to a string to ensure this content is translated.`,\n location\n );\n\nexport const warnNonStringSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-string literal (${colorizeContent(value)}). Change the value to a string literal to ensure this content is translated.`,\n location\n );\n\nexport const warnAsyncUseGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found useGT() in an async function. Use getGT() instead, or make the function synchronous.`,\n location\n );\n\nexport const warnSyncGetGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found getGT() in a synchronous function. Use useGT() instead, or make the function async.`,\n location\n );\n\nexport const warnTernarySync = (file: string, location?: string): string =>\n withLocation(\n file,\n 'Found ternary expression. A Branch component may be more appropriate here.',\n location\n );\n\nexport const withLocation = (\n file: string,\n message: string,\n location?: string\n): string =>\n `${colorizeFilepath(file)}${location ? ` (${colorizeLine(location)})` : ''}: ${message}`;\n\nexport const warnFunctionNotFoundSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} definition could not be resolved. This might affect translation resolution for this ${colorizeComponent('<T>')} component.`,\n location\n );\n\nexport const warnInvalidDeclareVarNameSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid declareVar() $name tag. Must be a derivable (statically analyzable) expression. Received: ${colorizeContent(value)}.`,\n location\n );\n\nexport const warnDuplicateFunctionDefinitionSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is defined multiple times. Only the first definition will be used.`,\n location\n );\n\nexport const warnInvalidDeriveInitSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `The definition for ${colorizeFunctionName(functionName)} could not be resolved. When using arrow syntax to define a derivable (statically analyzable) function, the right hand side or the assignment MUST only contain the arrow function itself and no other expressions.\nExample: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = () => { ... }`)}\nInvalid: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = [() => { ... }][0]`)}`\n ),\n location\n );\n\nexport const warnDataAttrOnBranch = (\n file: string,\n attrName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent(`<${BRANCH_COMPONENT}>`)} component ignores attributes prefixed with ${colorizeIdString('\"data-\"')}. Found ${colorizeIdString(attrName)}. Remove it or use a different attribute name.`,\n location\n );\n\nexport const warnRecursiveFunctionCallSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Recursive function call detected: ${colorizeFunctionName(functionName)}. A derivable (statically analyzable) function cannot use recursive calls to construct its result.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNotWrappedSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. This call is not wrapped in derive(). Ensure the function is properly wrapped with derive() and does not have circular import dependencies.`\n ),\n location\n );\n\nexport const warnDeriveNonConstVariableSync = (\n file: string,\n varName: string,\n kind: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} is declared with '${kind}' but only 'const' declarations can be resolved statically. Change it to 'const'.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNoResultsSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. derive() can only receive function invocations and cannot use undefined values or looped calls to construct its result.`\n ),\n location\n );\n\nexport const warnAutoderiveNoResultsSync = (\n file: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Autoderive could not resolve ${colorizeFunctionName(formatCodeClamp(expression))}. Only function calls with statically determinable return values can be used directly in t(). Consider wrapping with derive() for explicit derivation, or use an interpolation variable instead.`,\n location\n );\n\nexport const warnDeriveUnresolvableValueSync = (\n file: string,\n key: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Object property ${colorizeFunctionName(formatCodeClamp(key))} could not be resolved to a static string value. Only string literals, template literals, conditionals, and function calls returning strings are supported.`\n ),\n location\n );\n\nexport const warnDeriveCircularSpreadSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Circular spread detected involving ${colorizeFunctionName(varName)}. Spread references that form a cycle cannot be resolved statically.`\n ),\n location\n );\n\nexport const warnDeriveDestructuringSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} uses destructuring syntax, which is not yet supported in derive(). Assign the value to a const variable directly instead.`\n ),\n location\n );\n\nexport const warnDeriveOptionalChainingSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Optional chaining (${colorizeFunctionName(formatCodeClamp(code))}) is not supported in derive(). Optional chaining implies the value could be undefined, which cannot be resolved statically. Use a non-optional access instead.`\n ),\n location\n );\n\nexport const warnUnresolvedImportSync = (\n file: string,\n functionName: string,\n importPath: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Could not resolve import ${colorizeFunctionName(importPath)} for function ${colorizeFunctionName(functionName)}. Translation strings inside this function will not be extracted.`,\n location\n );\n\n// Re-export error messages\nexport const noLocalesError = `No target locales were found. Add locales to gt.config.json or pass them with the --locales flag.`;\nexport const noDefaultLocaleError = `No default locale was found. Add defaultLocale to gt.config.json or pass it with --default-locale.`;\nexport const noFilesError = `The files configuration is missing or invalid. Check the files section in gt.config.json and try again.`;\nexport const noSourceFileError = `No source translation file was found. Check your translations directory and default locale configuration.`;\nexport const noApiKeyError = `No API key was found. Pass --api-key or set the GT_API_KEY environment variable.`;\nexport const devApiKeyError = `Development API keys cannot be used with the General Translation API. Use a production API key instead.\\nGenerate a production API key with: npx gt auth -t production`;\nexport const noProjectIdError = `No project ID was found. Pass --project-id, add projectId to gt.config.json, or set the GT_PROJECT_ID environment variable.`;\nexport const noVersionIdError = `No version ID was found. Pass --version-id or add _versionId to gt.config.json.`;\nexport const invalidConfigurationError = `The files configuration cannot be used for this operation. Provide a valid download configuration or set --publish true to upload translations to the CDN.`;\nexport const lottieTranslateError = `Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\\n 1. Stage the files for translation: npx gt stage\\n 2. Fetch the finished translations: npx gt download\\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.`;\nexport const branchResolutionError = `The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.`;\n\nexport const lottieExpressionsError = (files: string[]): string =>\n `The following Lottie file(s) use After Effects expressions, which contain executable code and are not supported yet:\\n${files\n .map((file) => ` - ${file}`)\n .join(\n '\\n'\n )}\\nRe-export the animation with expressions baked into keyframes (or removed), then try again.`;\n\nexport const withOriginalError = (message: string, error: unknown): string =>\n error != null ? `${message} Original error: ${String(error)}` : message;\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { SpinnerResult, ProgressResult } from '@clack/prompts';
2
2
  export type LogFormat = 'default' | 'json';
3
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
3
4
  /**
4
5
  * GT_LOG_FORMAT: default | json.
5
6
  * - If default, logs will be pretty-printed using @clack/prompts.
@@ -13,8 +14,20 @@ declare class Logger {
13
14
  private pinoLogger;
14
15
  private fileLogger;
15
16
  private logFormat;
17
+ private logLevel;
18
+ private quiet;
16
19
  private constructor();
17
20
  static getInstance(): Logger;
21
+ /**
22
+ * Enable or disable quiet mode. When quiet, informational chatter
23
+ * (info/step/success/message/debug/trace, spinners, progress bars, and
24
+ * command intro/outro markers) is suppressed on the console, while warnings
25
+ * and errors still print. Quiet wins over GT_LOG_LEVEL but never lowers an
26
+ * already-more-restrictive level. File logging is unaffected so an explicit
27
+ * GT_LOG_FILE still captures everything.
28
+ */
29
+ setQuiet(quiet: boolean): void;
30
+ isQuiet(): boolean;
18
31
  trace(message: string): void;
19
32
  debug(message: string): void;
20
33
  info(message: string): void;
@@ -29,6 +29,13 @@ function wrapTerminalSessionAware(target) {
29
29
  }
30
30
  return target;
31
31
  }
32
+ const LOG_LEVEL_RANK = {
33
+ debug: 10,
34
+ info: 20,
35
+ warn: 30,
36
+ error: 40
37
+ };
38
+ const QUIET_FLOOR_LEVEL = "warn";
32
39
  var MockSpinner = class {
33
40
  currentMessage = "";
34
41
  logger;
@@ -85,6 +92,8 @@ const logger = class Logger {
85
92
  pinoLogger = null;
86
93
  fileLogger = null;
87
94
  logFormat;
95
+ logLevel;
96
+ quiet = false;
88
97
  constructor() {
89
98
  const format = (process.env.GT_LOG_FORMAT || "default").toLowerCase();
90
99
  const logFile = process.env.GT_LOG_FILE;
@@ -98,6 +107,7 @@ const logger = class Logger {
98
107
  process.exit(1);
99
108
  }
100
109
  this.logFormat = format;
110
+ this.logLevel = logLevel;
101
111
  if (format === "json") this.pinoLogger = pino({
102
112
  level: logLevel,
103
113
  mixin: () => ({ logId: randomUUID() })
@@ -111,22 +121,37 @@ const logger = class Logger {
111
121
  if (!Logger.instance) Logger.instance = new Logger();
112
122
  return Logger.instance;
113
123
  }
124
+ /**
125
+ * Enable or disable quiet mode. When quiet, informational chatter
126
+ * (info/step/success/message/debug/trace, spinners, progress bars, and
127
+ * command intro/outro markers) is suppressed on the console, while warnings
128
+ * and errors still print. Quiet wins over GT_LOG_LEVEL but never lowers an
129
+ * already-more-restrictive level. File logging is unaffected so an explicit
130
+ * GT_LOG_FILE still captures everything.
131
+ */
132
+ setQuiet(quiet) {
133
+ this.quiet = quiet;
134
+ if (this.pinoLogger) this.pinoLogger.level = quiet ? LOG_LEVEL_RANK[this.logLevel] > LOG_LEVEL_RANK[QUIET_FLOOR_LEVEL] ? this.logLevel : QUIET_FLOOR_LEVEL : this.logLevel;
135
+ }
136
+ isQuiet() {
137
+ return this.quiet;
138
+ }
114
139
  trace(message) {
115
- if (this.logFormat === "default") {
140
+ if (!this.quiet) if (this.logFormat === "default") {
116
141
  endTerminalSession();
117
142
  log.message(message, { symbol: chalk.dim("•") });
118
143
  } else this.pinoLogger?.trace(message);
119
144
  this.fileLogger?.trace(message);
120
145
  }
121
146
  debug(message) {
122
- if (this.logFormat === "default") {
147
+ if (!this.quiet) if (this.logFormat === "default") {
123
148
  endTerminalSession();
124
149
  log.message(message, { symbol: chalk.dim("◆") });
125
150
  } else this.pinoLogger?.debug(message);
126
151
  this.fileLogger?.debug(message);
127
152
  }
128
153
  info(message) {
129
- if (this.logFormat === "default") {
154
+ if (!this.quiet) if (this.logFormat === "default") {
130
155
  endTerminalSession();
131
156
  log.info(message);
132
157
  } else this.pinoLogger?.info(message);
@@ -157,43 +182,45 @@ const logger = class Logger {
157
182
  this.fileLogger?.silent(message);
158
183
  }
159
184
  success(message) {
160
- if (this.logFormat === "default") {
185
+ if (!this.quiet) if (this.logFormat === "default") {
161
186
  endTerminalSession();
162
187
  log.success(message);
163
188
  } else this.pinoLogger?.info(message);
164
189
  this.fileLogger?.info(message);
165
190
  }
166
191
  step(message) {
167
- if (this.logFormat === "default") {
192
+ if (!this.quiet) if (this.logFormat === "default") {
168
193
  endTerminalSession();
169
194
  log.step(message);
170
195
  } else this.pinoLogger?.info(message);
171
196
  this.fileLogger?.info(message);
172
197
  }
173
198
  message(message, symbol) {
174
- if (this.logFormat === "default") {
199
+ if (!this.quiet) if (this.logFormat === "default") {
175
200
  endTerminalSession();
176
201
  log.message(message, symbol ? { symbol } : void 0);
177
202
  } else this.pinoLogger?.info(message);
178
203
  this.fileLogger?.info(message);
179
204
  }
180
205
  createSpinner(indicator = "timer") {
206
+ if (this.quiet) return new MockSpinner(this);
181
207
  if (this.logFormat === "default") return wrapTerminalSessionAware(spinner({ indicator }));
182
208
  else return new MockSpinner(this);
183
209
  }
184
210
  createProgressBar(total) {
211
+ if (this.quiet) return new MockProgress(total, this);
185
212
  if (this.logFormat === "default") return wrapTerminalSessionAware(progress({ max: total }));
186
213
  else return new MockProgress(total, this);
187
214
  }
188
215
  startCommand(message) {
189
- if (this.logFormat === "default") {
216
+ if (!this.quiet) if (this.logFormat === "default") {
190
217
  endTerminalSession();
191
218
  intro(chalk.cyan(message));
192
219
  } else this.info(`╭─ ${message}`);
193
220
  this.fileLogger?.info(`[START] ${message}`);
194
221
  }
195
222
  endCommand(message) {
196
- if (this.logFormat === "default") {
223
+ if (!this.quiet) if (this.logFormat === "default") {
197
224
  endTerminalSession();
198
225
  outro(chalk.cyan(message));
199
226
  } else this.info(`╰─ ${message}`);
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/console/logger.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { randomUUID } from 'node:crypto';\nimport { pino, destination } from 'pino';\nimport {\n log as clackLog,\n spinner,\n progress,\n intro,\n outro,\n} from '@clack/prompts';\nimport { endTerminalSession } from './terminalSession.js';\n\nimport type { Logger as PinoLogger } from 'pino';\nimport type { SpinnerResult, ProgressResult } from '@clack/prompts';\n\nfunction wrapTerminalSessionAware<T extends SpinnerResult | ProgressResult>(\n target: T\n): T {\n const start = target.start.bind(target);\n const stop = target.stop.bind(target);\n const message = target.message.bind(target);\n target.start = (msg?: string) => {\n endTerminalSession();\n return start(msg);\n };\n target.stop = (msg?: string, code?: number) => {\n endTerminalSession();\n return (stop as (m?: string, c?: number) => void)(msg, code);\n };\n target.message = (msg?: string) => {\n endTerminalSession();\n return message(msg);\n };\n if ('advance' in target) {\n const advance = target.advance.bind(target);\n target.advance = (amount: number, msg?: string) => {\n endTerminalSession();\n return advance(amount, msg);\n };\n }\n return target;\n}\n\nexport type LogFormat = 'default' | 'json';\n\n// Mock spinner that logs to console instead of updating terminal UI\nclass MockSpinner implements SpinnerResult {\n private currentMessage: string = '';\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n start(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n\n stop(message?: string): void {\n const msg = message || this.currentMessage;\n if (msg) {\n this.logger.info(`[Spinner] ${msg}`);\n }\n this.currentMessage = '';\n }\n\n message(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n}\n\n// Mock progress bar that logs to console instead of updating terminal UI\nclass MockProgress implements ProgressResult {\n private max: number;\n private current: number = 0;\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(max: number, logger: Logger) {\n this.max = max;\n this.logger = logger;\n }\n\n start(message?: string): void {\n const msg = message || 'Starting progress';\n this.logger.info(`[Progress] ${msg} (0/${this.max})`);\n }\n\n stop(message?: string): void {\n const msg = message || 'Complete';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n\n message(message?: string): void {\n if (message) {\n this.logger.info(`[Progress] ${message} (${this.current}/${this.max})`);\n }\n }\n\n advance(amount: number, message?: string): void {\n this.current += amount;\n const msg = message || 'Progress';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n}\n\n/**\n * GT_LOG_FORMAT: default | json.\n * - If default, logs will be pretty-printed using @clack/prompts.\n * - If json, logs will be written in JSON format to the console.\n * GT_LOG_FILE: If specified, logs will be written to the file.\n * GT_LOG_LEVEL: The level of logs to write. If not specified, defaults to 'info'.\n * - Valid levels: debug, info, warn, error.\n */\nclass Logger {\n private static instance: Logger;\n private pinoLogger: PinoLogger | null = null;\n private fileLogger: PinoLogger | null = null;\n private logFormat: LogFormat;\n\n private constructor() {\n // Read configuration from environment variables\n const format = (\n process.env.GT_LOG_FORMAT || 'default'\n ).toLowerCase() as LogFormat;\n const logFile = process.env.GT_LOG_FILE;\n const logLevel = process.env.GT_LOG_LEVEL || 'info';\n\n if (format !== 'default' && format !== 'json') {\n console.error('Invalid log format');\n process.exit(1);\n }\n if (\n logLevel !== 'debug' &&\n logLevel !== 'info' &&\n logLevel !== 'warn' &&\n logLevel !== 'error'\n ) {\n console.error('Invalid log level');\n process.exit(1);\n }\n\n this.logFormat = format;\n\n // Console output (stdout) - only for JSON format\n // For 'default' format, we use @clack/prompts directly\n if (format === 'json') {\n this.pinoLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(1)\n );\n }\n\n // File output (if specified) - always JSON format\n if (logFile) {\n this.fileLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(logFile)\n );\n }\n }\n\n static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n return Logger.instance;\n }\n\n // Standard logging methods\n trace(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have trace, use message\n clackLog.message(message, { symbol: chalk.dim('•') });\n } else {\n this.pinoLogger?.trace(message);\n }\n this.fileLogger?.trace(message);\n }\n\n debug(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have debug, use message\n clackLog.message(message, { symbol: chalk.dim('◆') });\n } else {\n this.pinoLogger?.debug(message);\n }\n this.fileLogger?.debug(message);\n }\n\n info(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.info(message);\n } else {\n this.pinoLogger?.info(message);\n }\n this.fileLogger?.info(message);\n }\n\n warn(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.warn(message);\n } else {\n this.pinoLogger?.warn(message);\n }\n this.fileLogger?.warn(message);\n }\n\n error(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message);\n } else {\n this.pinoLogger?.error(message);\n }\n this.fileLogger?.error(message);\n }\n\n fatal(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message); // @clack/prompts doesn't have fatal, use error\n } else {\n this.pinoLogger?.fatal(message);\n }\n this.fileLogger?.fatal(message);\n }\n\n silent(message: string): void {\n // Silent doesn't log to console, only to file\n this.fileLogger?.silent(message);\n }\n\n // @clack/prompts specific methods (for 'default' format)\n success(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.success(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n this.fileLogger?.info(message);\n }\n\n step(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.step(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n this.fileLogger?.info(message);\n }\n\n message(message: string, symbol?: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.message(message, symbol ? { symbol } : undefined);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n this.fileLogger?.info(message);\n }\n\n // Spinner functionality\n createSpinner(indicator: 'dots' | 'timer' = 'timer'): SpinnerResult {\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(spinner({ indicator }));\n } else {\n return new MockSpinner(this);\n }\n }\n\n // Progress bar functionality\n createProgressBar(total: number): ProgressResult {\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(progress({ max: total }));\n } else {\n return new MockProgress(total, this);\n }\n }\n\n // Command start/end markers\n startCommand(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n intro(chalk.cyan(message));\n } else {\n this.info(`╭─ ${message}`);\n }\n this.fileLogger?.info(`[START] ${message}`);\n }\n\n endCommand(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n outro(chalk.cyan(message));\n } else {\n this.info(`╰─ ${message}`);\n }\n this.fileLogger?.info(`[END] ${message}`);\n }\n\n // Flush logs to ensure they're written before process exit\n flush(): void {\n this.pinoLogger?.flush();\n this.fileLogger?.flush();\n }\n}\n\nexport const logger = Logger.getInstance();\n"],"mappings":"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"}
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/console/logger.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { randomUUID } from 'node:crypto';\nimport { pino, destination } from 'pino';\nimport {\n log as clackLog,\n spinner,\n progress,\n intro,\n outro,\n} from '@clack/prompts';\nimport { endTerminalSession } from './terminalSession.js';\n\nimport type { Logger as PinoLogger } from 'pino';\nimport type { SpinnerResult, ProgressResult } from '@clack/prompts';\n\nfunction wrapTerminalSessionAware<T extends SpinnerResult | ProgressResult>(\n target: T\n): T {\n const start = target.start.bind(target);\n const stop = target.stop.bind(target);\n const message = target.message.bind(target);\n target.start = (msg?: string) => {\n endTerminalSession();\n return start(msg);\n };\n target.stop = (msg?: string, code?: number) => {\n endTerminalSession();\n return (stop as (m?: string, c?: number) => void)(msg, code);\n };\n target.message = (msg?: string) => {\n endTerminalSession();\n return message(msg);\n };\n if ('advance' in target) {\n const advance = target.advance.bind(target);\n target.advance = (amount: number, msg?: string) => {\n endTerminalSession();\n return advance(amount, msg);\n };\n }\n return target;\n}\n\nexport type LogFormat = 'default' | 'json';\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n// Numeric ordering used to decide the quiet floor without lowering an\n// already-more-restrictive level chosen via GT_LOG_LEVEL.\nconst LOG_LEVEL_RANK: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\n// Under --quiet, informational output is suppressed but warnings and errors\n// still print, so the console never drops below this level.\nconst QUIET_FLOOR_LEVEL: LogLevel = 'warn';\n\n// Mock spinner that logs to console instead of updating terminal UI\nclass MockSpinner implements SpinnerResult {\n private currentMessage: string = '';\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n start(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n\n stop(message?: string): void {\n const msg = message || this.currentMessage;\n if (msg) {\n this.logger.info(`[Spinner] ${msg}`);\n }\n this.currentMessage = '';\n }\n\n message(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n}\n\n// Mock progress bar that logs to console instead of updating terminal UI\nclass MockProgress implements ProgressResult {\n private max: number;\n private current: number = 0;\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(max: number, logger: Logger) {\n this.max = max;\n this.logger = logger;\n }\n\n start(message?: string): void {\n const msg = message || 'Starting progress';\n this.logger.info(`[Progress] ${msg} (0/${this.max})`);\n }\n\n stop(message?: string): void {\n const msg = message || 'Complete';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n\n message(message?: string): void {\n if (message) {\n this.logger.info(`[Progress] ${message} (${this.current}/${this.max})`);\n }\n }\n\n advance(amount: number, message?: string): void {\n this.current += amount;\n const msg = message || 'Progress';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n}\n\n/**\n * GT_LOG_FORMAT: default | json.\n * - If default, logs will be pretty-printed using @clack/prompts.\n * - If json, logs will be written in JSON format to the console.\n * GT_LOG_FILE: If specified, logs will be written to the file.\n * GT_LOG_LEVEL: The level of logs to write. If not specified, defaults to 'info'.\n * - Valid levels: debug, info, warn, error.\n */\nclass Logger {\n private static instance: Logger;\n private pinoLogger: PinoLogger | null = null;\n private fileLogger: PinoLogger | null = null;\n private logFormat: LogFormat;\n private logLevel: LogLevel;\n private quiet = false;\n\n private constructor() {\n // Read configuration from environment variables\n const format = (\n process.env.GT_LOG_FORMAT || 'default'\n ).toLowerCase() as LogFormat;\n const logFile = process.env.GT_LOG_FILE;\n const logLevel = process.env.GT_LOG_LEVEL || 'info';\n\n if (format !== 'default' && format !== 'json') {\n console.error('Invalid log format');\n process.exit(1);\n }\n if (\n logLevel !== 'debug' &&\n logLevel !== 'info' &&\n logLevel !== 'warn' &&\n logLevel !== 'error'\n ) {\n console.error('Invalid log level');\n process.exit(1);\n }\n\n this.logFormat = format;\n this.logLevel = logLevel as LogLevel;\n\n // Console output (stdout) - only for JSON format\n // For 'default' format, we use @clack/prompts directly\n if (format === 'json') {\n this.pinoLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(1)\n );\n }\n\n // File output (if specified) - always JSON format\n if (logFile) {\n this.fileLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(logFile)\n );\n }\n }\n\n static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n return Logger.instance;\n }\n\n /**\n * Enable or disable quiet mode. When quiet, informational chatter\n * (info/step/success/message/debug/trace, spinners, progress bars, and\n * command intro/outro markers) is suppressed on the console, while warnings\n * and errors still print. Quiet wins over GT_LOG_LEVEL but never lowers an\n * already-more-restrictive level. File logging is unaffected so an explicit\n * GT_LOG_FILE still captures everything.\n */\n setQuiet(quiet: boolean): void {\n this.quiet = quiet;\n if (this.pinoLogger) {\n this.pinoLogger.level = quiet\n ? LOG_LEVEL_RANK[this.logLevel] > LOG_LEVEL_RANK[QUIET_FLOOR_LEVEL]\n ? this.logLevel\n : QUIET_FLOOR_LEVEL\n : this.logLevel;\n }\n }\n\n isQuiet(): boolean {\n return this.quiet;\n }\n\n // Standard logging methods\n trace(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have trace, use message\n clackLog.message(message, { symbol: chalk.dim('•') });\n } else {\n this.pinoLogger?.trace(message);\n }\n }\n this.fileLogger?.trace(message);\n }\n\n debug(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have debug, use message\n clackLog.message(message, { symbol: chalk.dim('◆') });\n } else {\n this.pinoLogger?.debug(message);\n }\n }\n this.fileLogger?.debug(message);\n }\n\n info(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.info(message);\n } else {\n this.pinoLogger?.info(message);\n }\n }\n this.fileLogger?.info(message);\n }\n\n warn(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.warn(message);\n } else {\n this.pinoLogger?.warn(message);\n }\n this.fileLogger?.warn(message);\n }\n\n error(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message);\n } else {\n this.pinoLogger?.error(message);\n }\n this.fileLogger?.error(message);\n }\n\n fatal(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message); // @clack/prompts doesn't have fatal, use error\n } else {\n this.pinoLogger?.fatal(message);\n }\n this.fileLogger?.fatal(message);\n }\n\n silent(message: string): void {\n // Silent doesn't log to console, only to file\n this.fileLogger?.silent(message);\n }\n\n // @clack/prompts specific methods (for 'default' format)\n success(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.success(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n }\n this.fileLogger?.info(message);\n }\n\n step(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.step(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n }\n this.fileLogger?.info(message);\n }\n\n message(message: string, symbol?: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.message(message, symbol ? { symbol } : undefined);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n }\n this.fileLogger?.info(message);\n }\n\n // Spinner functionality\n createSpinner(indicator: 'dots' | 'timer' = 'timer'): SpinnerResult {\n // Quiet mode suppresses spinner UI; the mock routes through the gated\n // info() so nothing reaches the console while file logging is preserved.\n if (this.quiet) {\n return new MockSpinner(this);\n }\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(spinner({ indicator }));\n } else {\n return new MockSpinner(this);\n }\n }\n\n // Progress bar functionality\n createProgressBar(total: number): ProgressResult {\n if (this.quiet) {\n return new MockProgress(total, this);\n }\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(progress({ max: total }));\n } else {\n return new MockProgress(total, this);\n }\n }\n\n // Command start/end markers\n startCommand(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n intro(chalk.cyan(message));\n } else {\n this.info(`╭─ ${message}`);\n }\n }\n this.fileLogger?.info(`[START] ${message}`);\n }\n\n endCommand(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n outro(chalk.cyan(message));\n } else {\n this.info(`╰─ ${message}`);\n }\n }\n this.fileLogger?.info(`[END] ${message}`);\n }\n\n // Flush logs to ensure they're written before process exit\n flush(): void {\n this.pinoLogger?.flush();\n this.fileLogger?.flush();\n }\n}\n\nexport const logger = Logger.getInstance();\n"],"mappings":"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"}
@@ -34,8 +34,10 @@ function exitSync(code) {
34
34
  process.exit(code);
35
35
  }
36
36
  function displayHeader(introString) {
37
- displayAsciiTitle();
38
- displayInitializingText();
37
+ if (!logger.isQuiet()) {
38
+ displayAsciiTitle();
39
+ displayInitializingText();
40
+ }
39
41
  if (introString) logger.startCommand(introString);
40
42
  }
41
43
  function displayAsciiTitle() {
@@ -1 +1 @@
1
- {"version":3,"file":"logging.js","names":[],"sources":["../../src/console/logging.ts"],"sourcesContent":["import {\n text,\n select,\n confirm,\n isCancel,\n cancel,\n multiselect,\n} from '@clack/prompts';\nimport type { Option } from '@clack/prompts';\nimport chalk from 'chalk';\nimport { getCLIVersion } from '../utils/packageJson.js';\nimport { logger } from './logger.js';\nimport { TEMPLATE_FILE_NAME } from '../utils/constants.js';\nimport { FileToUpload } from 'generaltranslation/types';\nimport { endTerminalSession, shouldUseInkPrompts } from './terminalSession.js';\nimport {\n parseLocaleList,\n validateLocale,\n validateLocaleList,\n} from './promptParsing.js';\n\nfunction cancelPromptAndExit(message: string): never {\n endTerminalSession();\n cancel(message);\n return exitSync(0);\n}\n\nasync function loadInkPrompts() {\n return import('./inkPrompts.js');\n}\n\nasync function runInkPrompt<T>(\n prompt: (prompts: Awaited<ReturnType<typeof loadInkPrompts>>) => Promise<{\n value?: T;\n cancelled: boolean;\n }>,\n cancelMessage = 'Operation cancelled'\n) {\n const result = await prompt(await loadInkPrompts());\n if (result.cancelled) {\n return cancelPromptAndExit(cancelMessage);\n }\n return result.value;\n}\n\n/**\n * Strip ANSI escape codes from a string (e.g., chalk color codes)\n */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex, no-useless-escape\n return str.replace(/\\x1B\\[[0-9;]*m/g, '');\n}\n\nexport function logErrorAndExit(message: string): never {\n logger.error(message);\n return exitSync(1);\n}\n\nexport function exitSync(code: number): never {\n // Flush logs before exit\n logger.flush();\n process.exit(code);\n}\n\n// GT specific logging\nexport function displayHeader(introString?: string) {\n displayAsciiTitle();\n displayInitializingText();\n\n if (introString) {\n logger.startCommand(introString);\n }\n}\n\nfunction displayAsciiTitle() {\n // eslint-disable-next-line no-console\n console.log(\n chalk.cyan(\n `\\n @@@@@@@@@@@@@@@@@@@@@@\n @@ @@@@@@@@@@@@ @@@@@@@\n @@ @@@ @ @\n@@ @@ @ @\n@@ @ @@@@@ @ @\n@@ @@ @@@ @ @ @\n @@ @@ @ @ @ @\n @@ @@@@@@@ @ @ @\n @@@@@@@@@ @ @`\n )\n );\n}\n\nfunction displayInitializingText() {\n const version = getCLIVersion();\n // eslint-disable-next-line no-console\n console.log(\n `\\n${chalk.bold.blue('General Translation, Inc.')}\n${chalk.dim('https://generaltranslation.com/docs')}\n${chalk.dim(`CLI Version: ${version}\\n`)}`\n );\n}\n\nexport function displayProjectId(projectId: string) {\n logger.message(\n chalk.dim(`Project ID: ${chalk.bold(projectId)}`),\n chalk.cyan('~')\n );\n}\n\nexport function displayResolvedPaths(resolvedPaths: [string, string][]) {\n const paths = resolvedPaths.map(([key, resolvedPath]) => {\n return chalk.dim(`'${chalk.white(key)}' → '${chalk.green(resolvedPath)}'`);\n });\n logger.step(`Resolved path aliases:\\n${paths.join('\\n')}`);\n}\n\nexport function displayCreatedConfigFile(configFilepath: string) {\n logger.step(`Created config file ${chalk.cyan(configFilepath)}`);\n}\n\nexport function displayUpdatedConfigFile(configFilepath: string) {\n logger.success(`Updated config file ${chalk.cyan(configFilepath)}`);\n}\n\nexport function displayUpdatedVersionsFile(versionFilepath: string) {\n logger.success(`Updated versions file ${chalk.cyan(versionFilepath)}`);\n}\n\n// Input prompts\nexport async function promptText({\n message,\n defaultValue,\n validate,\n}: {\n message: string;\n defaultValue?: string;\n validate?: (value: string) => boolean | string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string>((prompts) =>\n prompts.inkPromptText({ message, defaultValue, validate })\n )) ?? ''\n );\n }\n\n const result = await text({\n message,\n placeholder: defaultValue,\n validate: validate\n ? (value) => {\n const validation = validate(value || '');\n return validation === true ? undefined : validation.toString();\n }\n : undefined,\n });\n\n if (isCancel(result)) {\n cancel('Operation cancelled');\n return exitSync(0);\n }\n\n return result;\n}\n\nexport async function promptLocale({\n message,\n defaultValue,\n}: {\n message: string;\n defaultValue?: string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string>((prompts) =>\n prompts.inkPromptLocale({ message, defaultValue })\n )) ?? ''\n );\n }\n\n return promptText({\n message,\n defaultValue,\n validate: validateLocale,\n });\n}\n\nexport async function promptLocaleList({\n message,\n defaultValue,\n required = true,\n}: {\n message: string;\n defaultValue?: string[];\n required?: boolean;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string[]>((prompts) =>\n prompts.inkPromptLocaleMulti({\n message,\n defaultValue,\n required,\n })\n )) ?? []\n );\n }\n\n return promptText({\n message,\n defaultValue: defaultValue?.join(' '),\n validate: validateLocaleList,\n }).then(parseLocaleList);\n}\n\nexport async function promptGlobPatterns({\n label,\n message,\n defaultValue,\n}: {\n label: string;\n message: string;\n defaultValue?: string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string>((prompts) =>\n prompts.inkPromptGlob({ label, message, defaultValue })\n )) ?? ''\n );\n }\n\n return promptText({\n message,\n defaultValue,\n });\n}\n\nexport async function promptSelect<T>({\n message,\n options,\n defaultValue,\n}: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n defaultValue?: T;\n}) {\n if (shouldUseInkPrompts()) {\n return (await runInkPrompt<T>((prompts) =>\n prompts.inkPromptSelect({ message, options, defaultValue })\n )) as T;\n }\n\n // Convert options to the format expected by clack\n const clackOptions = options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint,\n })) as Option<T>[];\n\n const result = await select({\n message,\n options: clackOptions,\n initialValue: defaultValue,\n });\n\n if (isCancel(result)) {\n cancel('Operation cancelled');\n return exitSync(0);\n }\n\n return result as T;\n}\n\nexport async function promptMultiSelect<T extends string>({\n message,\n options,\n required = true,\n}: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n required?: boolean;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<Array<T>>((prompts) =>\n prompts.inkPromptMultiSelect({\n message,\n options,\n required,\n })\n )) ?? []\n );\n }\n\n // Convert options to the format expected by clack\n const clackOptions = options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint,\n })) as Option<T>[];\n\n const result = await multiselect({\n message,\n options: clackOptions,\n required,\n });\n\n if (isCancel(result)) {\n cancel('Operation cancelled');\n return exitSync(0);\n }\n\n return result as Array<T>;\n}\n\nexport async function promptConfirm({\n message,\n defaultValue = true,\n cancelMessage = 'Operation cancelled',\n}: {\n message: string;\n defaultValue?: boolean;\n cancelMessage?: string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<boolean>(\n (prompts) => prompts.inkPromptConfirm({ message, defaultValue }),\n cancelMessage\n )) ?? defaultValue\n );\n }\n\n const result = await confirm({\n message,\n initialValue: defaultValue,\n });\n\n if (isCancel(result)) {\n cancel(cancelMessage);\n return exitSync(0);\n }\n\n return result;\n}\n\n// Warning display functions\nexport function warnApiKeyInConfig(optionsFilepath: string) {\n logger.warn(\n `Found ${chalk.cyan('apiKey')} in \"${chalk.green(optionsFilepath)}\". ` +\n chalk.white(\n 'Your API key is exposed! Remove it from the file and include it as an environment variable.'\n )\n );\n}\n\nexport function warnVariableProp(\n file: string,\n attrName: string,\n value: string\n) {\n logger.warn(\n `Found ${chalk.green('<T>')} component in ${chalk.cyan(file)} with variable ${attrName}: \"${chalk.white(value)}\". ` +\n `Change \"${attrName}\" to ensure this content is translated.`\n );\n}\n\nexport function warnNoId(file: string) {\n logger.warn(\n `Found ${chalk.green('<T>')} component in ${chalk.cyan(file)} with no id. ` +\n chalk.white('Add an id to ensure the content is translated.')\n );\n}\n\nexport function warnHasUnwrappedExpression(\n file: string,\n id: string,\n unwrappedExpressions: string[]\n) {\n logger.warn(\n `${chalk.green('<T>')} with id \"${id}\" in ${chalk.cyan(file)} has children: ${unwrappedExpressions.join(', ')} that could change at runtime. ` +\n chalk.white('Use a variable component like ') +\n chalk.green('<Var>') +\n chalk.white(' (') +\n chalk.blue('https://generaltranslation.com/docs') +\n chalk.white(') to translate this properly.')\n );\n}\n\nexport function warnTemplateLiteral(file: string, value: string) {\n logger.warn(\n `Found template literal with quasis (${value}) in ${chalk.cyan(file)}. ` +\n chalk.white(\n 'Change the template literal to a string to ensure this content is translated.'\n )\n );\n}\n\nexport function warnTernary(file: string) {\n logger.warn(\n `Found ternary expression in ${chalk.cyan(file)}. ` +\n chalk.white('A Branch component may be more appropriate here.')\n );\n}\n\nexport function warnDeprecatedField(\n deprecatedField: string,\n replacement: string\n) {\n logger.warn(\n `${chalk.green(deprecatedField)} is deprecated. ` +\n chalk.white(`Use ${chalk.green(replacement)} instead.`)\n );\n}\n\n/**\n * Helper: Log all collected files\n */\nexport function logCollectedFiles(\n files: Pick<FileToUpload, 'fileName'>[],\n reactComponents?: number\n): void {\n logger.message(\n chalk.cyan('Files found in project:') +\n '\\n' +\n files\n .map((file) => {\n if (file.fileName === TEMPLATE_FILE_NAME) {\n return `- <React Elements>${reactComponents ? ` (${reactComponents})` : ''}`;\n }\n return `- ${file.fileName}`;\n })\n .join('\\n')\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"logging.js","names":[],"sources":["../../src/console/logging.ts"],"sourcesContent":["import {\n text,\n select,\n confirm,\n isCancel,\n cancel,\n multiselect,\n} from '@clack/prompts';\nimport type { Option } from '@clack/prompts';\nimport chalk from 'chalk';\nimport { getCLIVersion } from '../utils/packageJson.js';\nimport { logger } from './logger.js';\nimport { TEMPLATE_FILE_NAME } from '../utils/constants.js';\nimport { FileToUpload } from 'generaltranslation/types';\nimport { endTerminalSession, shouldUseInkPrompts } from './terminalSession.js';\nimport {\n parseLocaleList,\n validateLocale,\n validateLocaleList,\n} from './promptParsing.js';\n\nfunction cancelPromptAndExit(message: string): never {\n endTerminalSession();\n cancel(message);\n return exitSync(0);\n}\n\nasync function loadInkPrompts() {\n return import('./inkPrompts.js');\n}\n\nasync function runInkPrompt<T>(\n prompt: (prompts: Awaited<ReturnType<typeof loadInkPrompts>>) => Promise<{\n value?: T;\n cancelled: boolean;\n }>,\n cancelMessage = 'Operation cancelled'\n) {\n const result = await prompt(await loadInkPrompts());\n if (result.cancelled) {\n return cancelPromptAndExit(cancelMessage);\n }\n return result.value;\n}\n\n/**\n * Strip ANSI escape codes from a string (e.g., chalk color codes)\n */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex, no-useless-escape\n return str.replace(/\\x1B\\[[0-9;]*m/g, '');\n}\n\nexport function logErrorAndExit(message: string): never {\n logger.error(message);\n return exitSync(1);\n}\n\nexport function exitSync(code: number): never {\n // Flush logs before exit\n logger.flush();\n process.exit(code);\n}\n\n// GT specific logging\nexport function displayHeader(introString?: string) {\n // The ASCII banner is pure chatter and writes to console directly, bypassing\n // the logger, so gate it here to honor --quiet. startCommand stays outside\n // the gate: it is quiet-aware itself and must still run so the file log\n // gets its [START] marker.\n if (!logger.isQuiet()) {\n displayAsciiTitle();\n displayInitializingText();\n }\n\n if (introString) {\n logger.startCommand(introString);\n }\n}\n\nfunction displayAsciiTitle() {\n // eslint-disable-next-line no-console\n console.log(\n chalk.cyan(\n `\\n @@@@@@@@@@@@@@@@@@@@@@\n @@ @@@@@@@@@@@@ @@@@@@@\n @@ @@@ @ @\n@@ @@ @ @\n@@ @ @@@@@ @ @\n@@ @@ @@@ @ @ @\n @@ @@ @ @ @ @\n @@ @@@@@@@ @ @ @\n @@@@@@@@@ @ @`\n )\n );\n}\n\nfunction displayInitializingText() {\n const version = getCLIVersion();\n // eslint-disable-next-line no-console\n console.log(\n `\\n${chalk.bold.blue('General Translation, Inc.')}\n${chalk.dim('https://generaltranslation.com/docs')}\n${chalk.dim(`CLI Version: ${version}\\n`)}`\n );\n}\n\nexport function displayProjectId(projectId: string) {\n logger.message(\n chalk.dim(`Project ID: ${chalk.bold(projectId)}`),\n chalk.cyan('~')\n );\n}\n\nexport function displayResolvedPaths(resolvedPaths: [string, string][]) {\n const paths = resolvedPaths.map(([key, resolvedPath]) => {\n return chalk.dim(`'${chalk.white(key)}' → '${chalk.green(resolvedPath)}'`);\n });\n logger.step(`Resolved path aliases:\\n${paths.join('\\n')}`);\n}\n\nexport function displayCreatedConfigFile(configFilepath: string) {\n logger.step(`Created config file ${chalk.cyan(configFilepath)}`);\n}\n\nexport function displayUpdatedConfigFile(configFilepath: string) {\n logger.success(`Updated config file ${chalk.cyan(configFilepath)}`);\n}\n\nexport function displayUpdatedVersionsFile(versionFilepath: string) {\n logger.success(`Updated versions file ${chalk.cyan(versionFilepath)}`);\n}\n\n// Input prompts\nexport async function promptText({\n message,\n defaultValue,\n validate,\n}: {\n message: string;\n defaultValue?: string;\n validate?: (value: string) => boolean | string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string>((prompts) =>\n prompts.inkPromptText({ message, defaultValue, validate })\n )) ?? ''\n );\n }\n\n const result = await text({\n message,\n placeholder: defaultValue,\n validate: validate\n ? (value) => {\n const validation = validate(value || '');\n return validation === true ? undefined : validation.toString();\n }\n : undefined,\n });\n\n if (isCancel(result)) {\n cancel('Operation cancelled');\n return exitSync(0);\n }\n\n return result;\n}\n\nexport async function promptLocale({\n message,\n defaultValue,\n}: {\n message: string;\n defaultValue?: string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string>((prompts) =>\n prompts.inkPromptLocale({ message, defaultValue })\n )) ?? ''\n );\n }\n\n return promptText({\n message,\n defaultValue,\n validate: validateLocale,\n });\n}\n\nexport async function promptLocaleList({\n message,\n defaultValue,\n required = true,\n}: {\n message: string;\n defaultValue?: string[];\n required?: boolean;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string[]>((prompts) =>\n prompts.inkPromptLocaleMulti({\n message,\n defaultValue,\n required,\n })\n )) ?? []\n );\n }\n\n return promptText({\n message,\n defaultValue: defaultValue?.join(' '),\n validate: validateLocaleList,\n }).then(parseLocaleList);\n}\n\nexport async function promptGlobPatterns({\n label,\n message,\n defaultValue,\n}: {\n label: string;\n message: string;\n defaultValue?: string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<string>((prompts) =>\n prompts.inkPromptGlob({ label, message, defaultValue })\n )) ?? ''\n );\n }\n\n return promptText({\n message,\n defaultValue,\n });\n}\n\nexport async function promptSelect<T>({\n message,\n options,\n defaultValue,\n}: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n defaultValue?: T;\n}) {\n if (shouldUseInkPrompts()) {\n return (await runInkPrompt<T>((prompts) =>\n prompts.inkPromptSelect({ message, options, defaultValue })\n )) as T;\n }\n\n // Convert options to the format expected by clack\n const clackOptions = options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint,\n })) as Option<T>[];\n\n const result = await select({\n message,\n options: clackOptions,\n initialValue: defaultValue,\n });\n\n if (isCancel(result)) {\n cancel('Operation cancelled');\n return exitSync(0);\n }\n\n return result as T;\n}\n\nexport async function promptMultiSelect<T extends string>({\n message,\n options,\n required = true,\n}: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n required?: boolean;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<Array<T>>((prompts) =>\n prompts.inkPromptMultiSelect({\n message,\n options,\n required,\n })\n )) ?? []\n );\n }\n\n // Convert options to the format expected by clack\n const clackOptions = options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint,\n })) as Option<T>[];\n\n const result = await multiselect({\n message,\n options: clackOptions,\n required,\n });\n\n if (isCancel(result)) {\n cancel('Operation cancelled');\n return exitSync(0);\n }\n\n return result as Array<T>;\n}\n\nexport async function promptConfirm({\n message,\n defaultValue = true,\n cancelMessage = 'Operation cancelled',\n}: {\n message: string;\n defaultValue?: boolean;\n cancelMessage?: string;\n}) {\n if (shouldUseInkPrompts()) {\n return (\n (await runInkPrompt<boolean>(\n (prompts) => prompts.inkPromptConfirm({ message, defaultValue }),\n cancelMessage\n )) ?? defaultValue\n );\n }\n\n const result = await confirm({\n message,\n initialValue: defaultValue,\n });\n\n if (isCancel(result)) {\n cancel(cancelMessage);\n return exitSync(0);\n }\n\n return result;\n}\n\n// Warning display functions\nexport function warnApiKeyInConfig(optionsFilepath: string) {\n logger.warn(\n `Found ${chalk.cyan('apiKey')} in \"${chalk.green(optionsFilepath)}\". ` +\n chalk.white(\n 'Your API key is exposed! Remove it from the file and include it as an environment variable.'\n )\n );\n}\n\nexport function warnVariableProp(\n file: string,\n attrName: string,\n value: string\n) {\n logger.warn(\n `Found ${chalk.green('<T>')} component in ${chalk.cyan(file)} with variable ${attrName}: \"${chalk.white(value)}\". ` +\n `Change \"${attrName}\" to ensure this content is translated.`\n );\n}\n\nexport function warnNoId(file: string) {\n logger.warn(\n `Found ${chalk.green('<T>')} component in ${chalk.cyan(file)} with no id. ` +\n chalk.white('Add an id to ensure the content is translated.')\n );\n}\n\nexport function warnHasUnwrappedExpression(\n file: string,\n id: string,\n unwrappedExpressions: string[]\n) {\n logger.warn(\n `${chalk.green('<T>')} with id \"${id}\" in ${chalk.cyan(file)} has children: ${unwrappedExpressions.join(', ')} that could change at runtime. ` +\n chalk.white('Use a variable component like ') +\n chalk.green('<Var>') +\n chalk.white(' (') +\n chalk.blue('https://generaltranslation.com/docs') +\n chalk.white(') to translate this properly.')\n );\n}\n\nexport function warnTemplateLiteral(file: string, value: string) {\n logger.warn(\n `Found template literal with quasis (${value}) in ${chalk.cyan(file)}. ` +\n chalk.white(\n 'Change the template literal to a string to ensure this content is translated.'\n )\n );\n}\n\nexport function warnTernary(file: string) {\n logger.warn(\n `Found ternary expression in ${chalk.cyan(file)}. ` +\n chalk.white('A Branch component may be more appropriate here.')\n );\n}\n\nexport function warnDeprecatedField(\n deprecatedField: string,\n replacement: string\n) {\n logger.warn(\n `${chalk.green(deprecatedField)} is deprecated. ` +\n chalk.white(`Use ${chalk.green(replacement)} instead.`)\n );\n}\n\n/**\n * Helper: Log all collected files\n */\nexport function logCollectedFiles(\n files: Pick<FileToUpload, 'fileName'>[],\n reactComponents?: number\n): void {\n logger.message(\n chalk.cyan('Files found in project:') +\n '\\n' +\n files\n .map((file) => {\n if (file.fileName === TEMPLATE_FILE_NAME) {\n return `- <React Elements>${reactComponents ? ` (${reactComponents})` : ''}`;\n }\n return `- ${file.fileName}`;\n })\n .join('\\n')\n );\n}\n"],"mappings":"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"}
@@ -1,12 +1,15 @@
1
1
  import { logger } from "../../console/logger.js";
2
2
  import { hashStringSync, hashVersionId } from "../../utils/hash.js";
3
- import { getRelative, readFile } from "../../fs/findFilepath.js";
3
+ import { logErrorAndExit } from "../../console/logging.js";
4
+ import { getRelative, readBinaryFileBase64, readFile } from "../../fs/findFilepath.js";
5
+ import { lottieExpressionsError } from "../../console/index.js";
4
6
  import { SUPPORTED_FILE_EXTENSIONS } from "./supportedFiles.js";
5
7
  import { getTransformFormatProperty } from "./transformFormat.js";
6
8
  import { determineLibrary } from "../../fs/determineFramework/index.js";
7
9
  import { flattenJson } from "../json/flattenJson.js";
8
10
  import { recordWarning } from "../../state/translateWarnings.js";
9
11
  import { buildPublishMap } from "../../utils/resolvePublish.js";
12
+ import { lottieHasExpressions } from "./detectLottieExpressions.js";
10
13
  import { parseJson } from "../json/parseJson.js";
11
14
  import { resolveMintlifyRefs, shouldResolveRefs } from "../../utils/resolveMintlifyRefs.js";
12
15
  import { storeRefMap } from "../../state/mintlifyRefMap.js";
@@ -177,8 +180,35 @@ async function aggregateFiles(settings) {
177
180
  });
178
181
  files.push(...twilioContentJsonFiles.filter((file) => file !== null));
179
182
  }
183
+ if (filePaths.lottie) {
184
+ const expressionOffenders = [];
185
+ const lottieFiles = filePaths.lottie.map((filePath) => {
186
+ const content = readBinaryFileBase64(filePath);
187
+ const relativePath = getRelative(filePath);
188
+ if (!content) {
189
+ logger.warn(`Skipping ${relativePath}: file is empty or unreadable`);
190
+ recordWarning("skipped_file", relativePath, "File is empty or unreadable");
191
+ return null;
192
+ }
193
+ if (lottieHasExpressions(content)) {
194
+ expressionOffenders.push(relativePath);
195
+ return null;
196
+ }
197
+ return {
198
+ content,
199
+ fileName: relativePath,
200
+ fileFormat: "LOTTIE",
201
+ ...getTransformFormatProperty(settings, "lottie"),
202
+ fileId: hashStringSync(relativePath),
203
+ versionId: hashStringSync(content),
204
+ locale: settings.defaultLocale
205
+ };
206
+ }).filter((file) => file !== null);
207
+ if (expressionOffenders.length > 0) logErrorAndExit(lottieExpressionsError(expressionOffenders));
208
+ files.push(...lottieFiles);
209
+ }
180
210
  for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
181
- if (fileType === "json" || fileType === "yaml" || fileType === "twilioContentJson") continue;
211
+ if (fileType === "json" || fileType === "yaml" || fileType === "twilioContentJson" || fileType === "lottie") continue;
182
212
  if (filePaths[fileType]) {
183
213
  const parsed = filePaths[fileType].map((filePath) => {
184
214
  const content = readFile(filePath);