gt 2.22.4 → 2.23.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 (127) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/auth/errors.d.ts +1 -0
  3. package/dist/auth/errors.js +12 -2
  4. package/dist/auth/errors.js.map +1 -1
  5. package/dist/auth/interactiveLogin.d.ts +2 -0
  6. package/dist/auth/interactiveLogin.js +22 -0
  7. package/dist/auth/interactiveLogin.js.map +1 -0
  8. package/dist/auth/oauth.js +2 -2
  9. package/dist/auth/oauth.js.map +1 -1
  10. package/dist/cli/base.d.ts +22 -4
  11. package/dist/cli/base.js +328 -223
  12. package/dist/cli/base.js.map +1 -1
  13. package/dist/cli/commands/api.js +15 -16
  14. package/dist/cli/commands/api.js.map +1 -1
  15. package/dist/cli/node.js +1 -1
  16. package/dist/cli/node.js.map +1 -1
  17. package/dist/cli/react.js +1 -1
  18. package/dist/cli/react.js.map +1 -1
  19. package/dist/cli/vue.js +2 -2
  20. package/dist/cli/vue.js.map +1 -1
  21. package/dist/config/generateSettings.d.ts +2 -0
  22. package/dist/config/generateSettings.js +13 -6
  23. package/dist/config/generateSettings.js.map +1 -1
  24. package/dist/config/resolveConfig.js +0 -4
  25. package/dist/config/resolveConfig.js.map +1 -1
  26. package/dist/config/validateSettings.js +5 -4
  27. package/dist/config/validateSettings.js.map +1 -1
  28. package/dist/console/{inkLocaleData.d.ts → localeOptions.d.ts} +7 -2
  29. package/dist/console/{inkLocaleData.js → localeOptions.js} +3 -8
  30. package/dist/console/localeOptions.js.map +1 -0
  31. package/dist/console/logger.d.ts +7 -0
  32. package/dist/console/logger.js +48 -85
  33. package/dist/console/logger.js.map +1 -1
  34. package/dist/console/logging.d.ts +11 -1
  35. package/dist/console/logging.js +88 -100
  36. package/dist/console/logging.js.map +1 -1
  37. package/dist/formats/files/aggregateFiles.js +1 -1
  38. package/dist/formats/files/supportedFiles.d.ts +3 -0
  39. package/dist/formats/files/supportedFiles.js +10 -1
  40. package/dist/formats/files/supportedFiles.js.map +1 -1
  41. package/dist/formats/yaml/mergeYaml.js +1 -1
  42. package/dist/fs/config/loadConfig.d.ts +2 -0
  43. package/dist/fs/config/loadConfig.js +5 -1
  44. package/dist/fs/config/loadConfig.js.map +1 -1
  45. package/dist/fs/config/setupConfig.d.ts +18 -9
  46. package/dist/fs/config/setupConfig.js +51 -31
  47. package/dist/fs/config/setupConfig.js.map +1 -1
  48. package/dist/fs/createLoadTranslationsFile.d.ts +22 -1
  49. package/dist/fs/createLoadTranslationsFile.js +43 -20
  50. package/dist/fs/createLoadTranslationsFile.js.map +1 -1
  51. package/dist/generated/version.d.ts +1 -1
  52. package/dist/generated/version.js +1 -1
  53. package/dist/generated/version.js.map +1 -1
  54. package/dist/hooks/postProcess.d.ts +1 -2
  55. package/dist/hooks/postProcess.js +1 -1
  56. package/dist/hooks/postProcess.js.map +1 -1
  57. package/dist/locadex/setupFlow.d.ts +4 -1
  58. package/dist/locadex/setupFlow.js +5 -3
  59. package/dist/locadex/setupFlow.js.map +1 -1
  60. package/dist/react/jsx/utils/jsxParsing/addGTIdentifierToSyntaxTree.js +1 -1
  61. package/dist/react/jsx/utils/jsxParsing/parseJsx.js +1 -1
  62. package/dist/react/jsx/utils/parseString.js +1 -1
  63. package/dist/react/jsx/utils/stringParsing/derivation/index.js +1 -1
  64. package/dist/setup/buildTools/index.d.ts +44 -0
  65. package/dist/setup/buildTools/index.js +10 -0
  66. package/dist/setup/buildTools/index.js.map +1 -0
  67. package/dist/setup/buildTools/vite.d.ts +2 -0
  68. package/dist/setup/buildTools/vite.js +61 -0
  69. package/dist/setup/buildTools/vite.js.map +1 -0
  70. package/dist/setup/developmentCredentials.d.ts +40 -5
  71. package/dist/setup/developmentCredentials.js +119 -37
  72. package/dist/setup/developmentCredentials.js.map +1 -1
  73. package/dist/setup/instructions/base.md +1 -1
  74. package/dist/setup/onboarding.d.ts +131 -0
  75. package/dist/setup/onboarding.js +289 -0
  76. package/dist/setup/onboarding.js.map +1 -0
  77. package/dist/setup/setupTarget.d.ts +1 -0
  78. package/dist/setup/setupTarget.js +52 -0
  79. package/dist/setup/setupTarget.js.map +1 -0
  80. package/dist/setup/setupViteSPA.d.ts +32 -1
  81. package/dist/setup/setupViteSPA.js +110 -20
  82. package/dist/setup/setupViteSPA.js.map +1 -1
  83. package/dist/setup/userInput.d.ts +12 -3
  84. package/dist/setup/userInput.js +27 -11
  85. package/dist/setup/userInput.js.map +1 -1
  86. package/dist/setup/wizard.d.ts +19 -3
  87. package/dist/setup/wizard.js +119 -105
  88. package/dist/setup/wizard.js.map +1 -1
  89. package/dist/types/index.d.ts +2 -1
  90. package/dist/types/index.js +13 -1
  91. package/dist/types/index.js.map +1 -0
  92. package/dist/utils/credentials.d.ts +9 -6
  93. package/dist/utils/credentials.js +36 -22
  94. package/dist/utils/credentials.js.map +1 -1
  95. package/dist/utils/monorepoVersionCheck.d.ts +1 -1
  96. package/dist/utils/monorepoVersionCheck.js +5 -5
  97. package/dist/utils/monorepoVersionCheck.js.map +1 -1
  98. package/dist/utils/packageManager.js +13 -14
  99. package/dist/utils/packageManager.js.map +1 -1
  100. package/package.json +5 -9
  101. package/dist/console/inkFields.d.ts +0 -23
  102. package/dist/console/inkFields.js +0 -88
  103. package/dist/console/inkFields.js.map +0 -1
  104. package/dist/console/inkLayout.d.ts +0 -7
  105. package/dist/console/inkLayout.js +0 -140
  106. package/dist/console/inkLayout.js.map +0 -1
  107. package/dist/console/inkLocaleData.js.map +0 -1
  108. package/dist/console/inkPrompts.d.ts +0 -8
  109. package/dist/console/inkPrompts.js +0 -499
  110. package/dist/console/inkPrompts.js.map +0 -1
  111. package/dist/console/inkSession.d.ts +0 -3
  112. package/dist/console/inkSession.js +0 -42
  113. package/dist/console/inkSession.js.map +0 -1
  114. package/dist/console/inkTerminal.d.ts +0 -4
  115. package/dist/console/inkTerminal.js +0 -15
  116. package/dist/console/inkTerminal.js.map +0 -1
  117. package/dist/console/inkTheme.d.ts +0 -1
  118. package/dist/console/inkTheme.js +0 -6
  119. package/dist/console/inkTheme.js.map +0 -1
  120. package/dist/console/inkTypes.d.ts +0 -69
  121. package/dist/console/inkTypes.js +0 -1
  122. package/dist/console/inkUtils.d.ts +0 -24
  123. package/dist/console/inkUtils.js +0 -87
  124. package/dist/console/inkUtils.js.map +0 -1
  125. package/dist/console/terminalSession.d.ts +0 -5
  126. package/dist/console/terminalSession.js +0 -38
  127. package/dist/console/terminalSession.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"setupConfig.js","names":[],"sources":["../../../src/fs/config/setupConfig.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { displayCreatedConfigFile } from '../../console/logging.js';\nimport { FilesOptions, SupportedFrameworks } from '../../types/index.js';\nimport { logger } from '../../console/logger.js';\nimport { GT_CONFIG_SCHEMA_URL } from '../../utils/constants.js';\n\n/**\n * Checks if the config file exists.\n * If yes, make sure make sure projectId is correct\n * If not, creates a new JSON file at the given filepath and writes the provided config object to it.\n * @param {string} configFilepath - The path to the config file.\n * @param {Record<string, any>} configObject - The config object to write if the file does not exist.\n */\nexport async function createOrUpdateConfig(\n configFilepath: string,\n options: {\n projectId?: string;\n defaultLocale?: string;\n locales?: string[];\n src?: string[];\n files?: FilesOptions;\n framework?: SupportedFrameworks;\n baseUrl?: string;\n publish?: boolean;\n /** Removes stale global CDN intent when the selected runtime forbids it. */\n clearPublish?: boolean;\n }\n): Promise<string> {\n // Filter out empty string values from the config object\n const newContent = {\n ...(options.projectId && { projectId: options.projectId }),\n ...(options.defaultLocale && { defaultLocale: options.defaultLocale }),\n ...(options.src && { src: options.src }),\n ...(options.files && { files: options.files }),\n ...(options.framework && { framework: options.framework }),\n ...(options.baseUrl && { baseUrl: options.baseUrl }),\n ...(options.publish && { publish: options.publish }),\n };\n try {\n // if file exists\n let oldContent: Record<string, unknown> = {};\n if (fs.existsSync(configFilepath)) {\n const parsed = JSON.parse(\n await fs.promises.readFile(configFilepath, 'utf-8')\n );\n oldContent =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n }\n\n // merge old and new content\n const mergedContent = {\n $schema: GT_CONFIG_SCHEMA_URL,\n ...oldContent,\n ...newContent,\n } as Record<string, unknown> & { locales?: string[] };\n\n if (options.clearPublish) {\n delete mergedContent.publish;\n }\n\n // Preserve unrelated file configuration and nested GT options when setup\n // only needs to add or update a translation output path.\n if (options.files) {\n const oldFiles =\n oldContent.files && typeof oldContent.files === 'object'\n ? (oldContent.files as Record<string, unknown>)\n : {};\n const oldGt =\n oldFiles.gt && typeof oldFiles.gt === 'object'\n ? (oldFiles.gt as Record<string, unknown>)\n : {};\n mergedContent.files = {\n ...oldFiles,\n ...options.files,\n ...(options.files.gt && {\n gt: { ...oldGt, ...options.files.gt },\n }),\n };\n }\n\n // Add locales to mergedContent if they exist\n if (options.locales) {\n mergedContent.locales = mergedContent.locales\n ? [...new Set([...mergedContent.locales, ...options.locales])]\n : options.locales;\n }\n\n // write to file\n const mergedJsonContent = JSON.stringify(mergedContent, null, 2);\n await fs.promises.writeFile(configFilepath, mergedJsonContent, 'utf-8');\n\n // show update in console\n displayCreatedConfigFile(configFilepath);\n } catch (error) {\n logger.error(\n `An error occurred while updating ${configFilepath}: ${error}`\n );\n }\n return configFilepath;\n}\n"],"mappings":";;;;;;;;;;;;AAaA,eAAsB,qBACpB,gBACA,SAYiB;CAEjB,MAAM,aAAa;EACjB,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,WAAW;EACzD,GAAI,QAAQ,iBAAiB,EAAE,eAAe,QAAQ,eAAe;EACrE,GAAI,QAAQ,OAAO,EAAE,KAAK,QAAQ,KAAK;EACvC,GAAI,QAAQ,SAAS,EAAE,OAAO,QAAQ,OAAO;EAC7C,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,WAAW;EACzD,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,SAAS;EACnD,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,SAAS;EACpD;AACD,KAAI;EAEF,IAAI,aAAsC,EAAE;AAC5C,MAAI,GAAG,WAAW,eAAe,EAAE;GACjC,MAAM,SAAS,KAAK,MAClB,MAAM,GAAG,SAAS,SAAS,gBAAgB,QAAQ,CACpD;AACD,gBACE,OAAO,WAAW,YAAY,WAAW,OACpC,SACD,EAAE;;EAIV,MAAM,gBAAgB;GACpB,SAAS;GACT,GAAG;GACH,GAAG;GACJ;AAED,MAAI,QAAQ,aACV,QAAO,cAAc;AAKvB,MAAI,QAAQ,OAAO;GACjB,MAAM,WACJ,WAAW,SAAS,OAAO,WAAW,UAAU,WAC3C,WAAW,QACZ,EAAE;GACR,MAAM,QACJ,SAAS,MAAM,OAAO,SAAS,OAAO,WACjC,SAAS,KACV,EAAE;AACR,iBAAc,QAAQ;IACpB,GAAG;IACH,GAAG,QAAQ;IACX,GAAI,QAAQ,MAAM,MAAM,EACtB,IAAI;KAAE,GAAG;KAAO,GAAG,QAAQ,MAAM;KAAI,EACtC;IACF;;AAIH,MAAI,QAAQ,QACV,eAAc,UAAU,cAAc,UAClC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,cAAc,SAAS,GAAG,QAAQ,QAAQ,CAAC,CAAC,GAC5D,QAAQ;EAId,MAAM,oBAAoB,KAAK,UAAU,eAAe,MAAM,EAAE;AAChE,QAAM,GAAG,SAAS,UAAU,gBAAgB,mBAAmB,QAAQ;AAGvE,2BAAyB,eAAe;UACjC,OAAO;AACd,SAAO,MACL,oCAAoC,eAAe,IAAI,QACxD;;AAEH,QAAO"}
1
+ {"version":3,"file":"setupConfig.js","names":[],"sources":["../../../src/fs/config/setupConfig.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { displayCreatedConfigFile } from '../../console/logging.js';\nimport { FilesOptions, SupportedFrameworks } from '../../types/index.js';\nimport {\n createDiagnosticMessage,\n formatDiagnosticErrorDetails,\n} from 'generaltranslation/internal';\nimport { GT_CONFIG_SCHEMA_URL } from '../../utils/constants.js';\n\nexport type SetupConfigUpdate = {\n projectId?: string;\n defaultLocale?: string;\n locales?: string[];\n src?: string[];\n files?: FilesOptions;\n framework?: SupportedFrameworks;\n baseUrl?: string;\n publish?: boolean;\n /** Removes stale global CDN intent when the selected runtime forbids it. */\n clearPublish?: boolean;\n /** File format entries deselected by an explicit format list. */\n removeFiles?: string[];\n /** Drops files.gt.output after an explicit switch to CDN storage. */\n clearGtOutput?: boolean;\n};\n\nfunction asObject(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/**\n * The config setup writes: the existing content with the update applied.\n * Unrelated fields and per-format options are kept; locales are replaced.\n */\nexport function mergeSetupConfig(\n oldContent: Record<string, unknown>,\n options: SetupConfigUpdate\n): Record<string, unknown> {\n // Filter out empty string values from the config object\n const newContent = {\n ...(options.projectId && { projectId: options.projectId }),\n ...(options.defaultLocale && { defaultLocale: options.defaultLocale }),\n ...(options.src && { src: options.src }),\n ...(options.framework && { framework: options.framework }),\n ...(options.baseUrl && { baseUrl: options.baseUrl }),\n ...(options.publish && { publish: options.publish }),\n };\n const mergedContent: Record<string, unknown> = {\n $schema: GT_CONFIG_SCHEMA_URL,\n ...oldContent,\n ...newContent,\n };\n\n if (options.clearPublish) {\n delete mergedContent.publish;\n }\n\n // Preserve unrelated file configuration and nested GT options when setup\n // only needs to add or update a translation output path.\n if (options.files || options.removeFiles?.length || options.clearGtOutput) {\n const oldFiles = asObject(oldContent.files);\n const files: Record<string, unknown> = { ...oldFiles, ...options.files };\n const gt = { ...asObject(oldFiles.gt), ...options.files?.gt };\n if (options.clearGtOutput) delete gt.output;\n if (Object.keys(gt).length > 0) files.gt = gt;\n else delete files.gt;\n for (const format of options.removeFiles ?? []) delete files[format];\n if (Object.keys(files).length > 0) mergedContent.files = files;\n else delete mergedContent.files;\n }\n\n // The selected locale list replaces the configured one.\n if (options.locales) {\n mergedContent.locales = options.locales;\n }\n return mergedContent;\n}\n\n/**\n * Creates the config file, or applies the update to the existing one.\n * @param {string} configFilepath - The path to the config file.\n * @param {SetupConfigUpdate} options - The values setup resolved.\n * @throws When the existing file is not valid JSON or cannot be written.\n */\nexport async function createOrUpdateConfig(\n configFilepath: string,\n options: SetupConfigUpdate\n): Promise<string> {\n try {\n let oldContent: Record<string, unknown> = {};\n if (fs.existsSync(configFilepath)) {\n const parsed = JSON.parse(\n await fs.promises.readFile(configFilepath, 'utf-8')\n );\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n Array.isArray(parsed)\n )\n throw new Error('the file does not contain a JSON object');\n oldContent = parsed as Record<string, unknown>;\n }\n\n const mergedJsonContent = JSON.stringify(\n mergeSetupConfig(oldContent, options),\n null,\n 2\n );\n await fs.promises.writeFile(configFilepath, mergedJsonContent, 'utf-8');\n\n // show update in console\n displayCreatedConfigFile(configFilepath);\n } catch (error) {\n throw new Error(\n createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: `Could not update ${configFilepath}`,\n details: formatDiagnosticErrorDetails(error),\n fix: 'Fix or remove the file, then rerun the command',\n })\n );\n }\n return configFilepath;\n}\n"],"mappings":";;;;;AA0BA,SAAS,SAAS,OAAyC;AACzD,QAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,GAC7D,QACD,EAAE;;;;;;AAOR,SAAgB,iBACd,YACA,SACyB;CAEzB,MAAM,aAAa;EACjB,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,WAAW;EACzD,GAAI,QAAQ,iBAAiB,EAAE,eAAe,QAAQ,eAAe;EACrE,GAAI,QAAQ,OAAO,EAAE,KAAK,QAAQ,KAAK;EACvC,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,WAAW;EACzD,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,SAAS;EACnD,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,SAAS;EACpD;CACD,MAAM,gBAAyC;EAC7C,SAAS;EACT,GAAG;EACH,GAAG;EACJ;AAED,KAAI,QAAQ,aACV,QAAO,cAAc;AAKvB,KAAI,QAAQ,SAAS,QAAQ,aAAa,UAAU,QAAQ,eAAe;EACzE,MAAM,WAAW,SAAS,WAAW,MAAM;EAC3C,MAAM,QAAiC;GAAE,GAAG;GAAU,GAAG,QAAQ;GAAO;EACxE,MAAM,KAAK;GAAE,GAAG,SAAS,SAAS,GAAG;GAAE,GAAG,QAAQ,OAAO;GAAI;AAC7D,MAAI,QAAQ,cAAe,QAAO,GAAG;AACrC,MAAI,OAAO,KAAK,GAAG,CAAC,SAAS,EAAG,OAAM,KAAK;MACtC,QAAO,MAAM;AAClB,OAAK,MAAM,UAAU,QAAQ,eAAe,EAAE,CAAE,QAAO,MAAM;AAC7D,MAAI,OAAO,KAAK,MAAM,CAAC,SAAS,EAAG,eAAc,QAAQ;MACpD,QAAO,cAAc;;AAI5B,KAAI,QAAQ,QACV,eAAc,UAAU,QAAQ;AAElC,QAAO;;;;;;;;AAST,eAAsB,qBACpB,gBACA,SACiB;AACjB,KAAI;EACF,IAAI,aAAsC,EAAE;AAC5C,MAAI,GAAG,WAAW,eAAe,EAAE;GACjC,MAAM,SAAS,KAAK,MAClB,MAAM,GAAG,SAAS,SAAS,gBAAgB,QAAQ,CACpD;AACD,OACE,OAAO,WAAW,YAClB,WAAW,QACX,MAAM,QAAQ,OAAO,CAErB,OAAM,IAAI,MAAM,0CAA0C;AAC5D,gBAAa;;EAGf,MAAM,oBAAoB,KAAK,UAC7B,iBAAiB,YAAY,QAAQ,EACrC,MACA,EACD;AACD,QAAM,GAAG,SAAS,UAAU,gBAAgB,mBAAmB,QAAQ;AAGvE,2BAAyB,eAAe;UACjC,OAAO;AACd,QAAM,IAAI,MACR,wBAAwB;GACtB,QAAQ;GACR,UAAU;GACV,cAAc,oBAAoB;GAClC,SAAS,6BAA6B,MAAM;GAC5C,KAAK;GACN,CAAC,CACH;;AAEH,QAAO"}
@@ -1 +1,22 @@
1
- export declare function createLoadTranslationsFile(appDirectory: string, translationsDir: string | undefined, locales: string[]): Promise<void>;
1
+ /**
2
+ * Every loadTranslations file the app has, in gt-next's lookup order
3
+ * (resolveConfigFilepath): root before src, .ts before .js. gt-next uses the
4
+ * first one, and falls back to the next when it is deleted.
5
+ */
6
+ export declare function findLoadTranslationsFiles(appDirectory: string): string[];
7
+ export type LoadTranslationsFileResult = 'created' | 'updated' | 'unchanged' | 'custom';
8
+ /**
9
+ * Creates or updates the generated loadTranslations.js for translationsDir
10
+ * (relative to appDirectory) and empty stubs for non-default locales. A
11
+ * loader that was not matching the previous config's generated template, or
12
+ * another loadTranslations file the app uses instead, is left untouched and
13
+ * reported as 'custom'.
14
+ * Directory and stub failures propagate.
15
+ */
16
+ export declare function createLoadTranslationsFile({ appDirectory, translationsDir, defaultLocale, locales, previousTranslationsDir, }: {
17
+ appDirectory: string;
18
+ translationsDir?: string;
19
+ defaultLocale: string;
20
+ locales: string[];
21
+ previousTranslationsDir?: string;
22
+ }): Promise<LoadTranslationsFileResult>;
@@ -9,13 +9,8 @@ function toRelativeImportPath(relativePath) {
9
9
  if (!normalizedPath) return "./";
10
10
  return normalizedPath === ".." || normalizedPath.startsWith("../") || normalizedPath.startsWith("./") ? `${normalizedPath}/` : `./${normalizedPath}/`;
11
11
  }
12
- async function createLoadTranslationsFile(appDirectory, translationsDir = DEFAULT_TRANSLATIONS_DIR, locales) {
13
- const usingSrcDirectory = fs.existsSync(path.join(appDirectory, "src"));
14
- const loadTranslationsDir = usingSrcDirectory ? path.join(appDirectory, "src") : appDirectory;
15
- const publicPath = toRelativeImportPath(path.relative(loadTranslationsDir, path.resolve(appDirectory, translationsDir)));
16
- const filePath = usingSrcDirectory ? path.join(appDirectory, "src", "loadTranslations.js") : path.join(appDirectory, "loadTranslations.js");
17
- if (!fs.existsSync(filePath)) {
18
- const loadTranslationsContent = `
12
+ function getLoaderContent(translationsDir, publicPath) {
13
+ return `
19
14
  export default async function loadTranslations(locale) {
20
15
  try {
21
16
  // Load translations from ${translationsDir} directory
@@ -28,20 +23,48 @@ export default async function loadTranslations(locale) {
28
23
  }
29
24
  }
30
25
  `;
31
- await fs.promises.writeFile(filePath, loadTranslationsContent);
32
- logger.info(`Created ${chalk.cyan("loadTranslations.js")} file at ${chalk.cyan(filePath)}.`);
33
- try {
34
- await fs.promises.mkdir(translationsDir, { recursive: true });
35
- for (const locale of locales) {
36
- if (fs.existsSync(path.join(translationsDir, `${locale}.json`))) continue;
37
- await fs.promises.writeFile(path.join(translationsDir, `${locale}.json`), "{}");
38
- }
39
- } catch (error) {
40
- logger.error(`Failed to create translations directory: ${error}`);
41
- }
42
- } else logger.info(`Found ${chalk.cyan("loadTranslations.js")} file at ${chalk.cyan(filePath)}. Skipping creation...`);
26
+ }
27
+ /**
28
+ * Every loadTranslations file the app has, in gt-next's lookup order
29
+ * (resolveConfigFilepath): root before src, .ts before .js. gt-next uses the
30
+ * first one, and falls back to the next when it is deleted.
31
+ */
32
+ function findLoadTranslationsFiles(appDirectory) {
33
+ return ["", "src"].flatMap((directory) => [".ts", ".js"].map((extension) => path.join(appDirectory, directory, `loadTranslations${extension}`))).filter((candidate) => fs.existsSync(candidate));
34
+ }
35
+ /**
36
+ * Creates or updates the generated loadTranslations.js for translationsDir
37
+ * (relative to appDirectory) and empty stubs for non-default locales. A
38
+ * loader that was not matching the previous config's generated template, or
39
+ * another loadTranslations file the app uses instead, is left untouched and
40
+ * reported as 'custom'.
41
+ * Directory and stub failures propagate.
42
+ */
43
+ async function createLoadTranslationsFile({ appDirectory, translationsDir = DEFAULT_TRANSLATIONS_DIR, defaultLocale, locales, previousTranslationsDir }) {
44
+ const loadTranslationsDir = fs.existsSync(path.join(appDirectory, "src")) ? path.join(appDirectory, "src") : appDirectory;
45
+ const translationsPath = path.resolve(appDirectory, translationsDir);
46
+ const publicPath = toRelativeImportPath(path.relative(loadTranslationsDir, translationsPath));
47
+ const filePath = path.join(loadTranslationsDir, "loadTranslations.js");
48
+ const content = getLoaderContent(translationsDir, publicPath);
49
+ const previousContents = previousTranslationsDir === void 0 ? [] : [previousTranslationsDir, ...!path.isAbsolute(previousTranslationsDir) ? [`./${previousTranslationsDir}`] : []].flatMap((directory) => [directory, `${directory}/`]).map((directory) => getLoaderContent(directory, toRelativeImportPath(path.relative(loadTranslationsDir, path.resolve(appDirectory, previousTranslationsDir)))));
50
+ const [loaderPath] = findLoadTranslationsFiles(appDirectory);
51
+ const existing = loaderPath === filePath ? await fs.promises.readFile(filePath, "utf8") : void 0;
52
+ await fs.promises.mkdir(translationsPath, { recursive: true });
53
+ for (const locale of new Set(locales)) {
54
+ if (locale === defaultLocale) continue;
55
+ const stubPath = path.join(translationsPath, `${locale}.json`);
56
+ if (!fs.existsSync(stubPath)) await fs.promises.writeFile(stubPath, "{}");
57
+ }
58
+ if (loaderPath !== void 0 && loaderPath !== filePath || existing !== void 0 && existing !== content && !previousContents.includes(existing)) {
59
+ logger.info(`Found a custom ${chalk.cyan(path.basename(loaderPath ?? filePath))} at ${chalk.cyan(loaderPath ?? filePath)}; leaving it unchanged.`);
60
+ return "custom";
61
+ }
62
+ if (existing === content) return "unchanged";
63
+ await fs.promises.writeFile(filePath, content);
64
+ logger.info(`${existing === void 0 ? "Created" : "Updated"} ${chalk.cyan("loadTranslations.js")} at ${chalk.cyan(filePath)}.`);
65
+ return existing === void 0 ? "created" : "updated";
43
66
  }
44
67
  //#endregion
45
- export { createLoadTranslationsFile };
68
+ export { createLoadTranslationsFile, findLoadTranslationsFiles };
46
69
 
47
70
  //# sourceMappingURL=createLoadTranslationsFile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createLoadTranslationsFile.js","names":[],"sources":["../../src/fs/createLoadTranslationsFile.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from '../console/logger.js';\nimport chalk from 'chalk';\nimport { DEFAULT_TRANSLATIONS_DIR } from '../utils/constants.js';\n\nfunction toRelativeImportPath(relativePath: string) {\n const normalizedPath = relativePath.split(path.sep).join(path.posix.sep);\n\n if (!normalizedPath) {\n return './';\n }\n\n // Dynamic imports must use explicit relative specifiers; values like\n // \"src/_gt\" are otherwise treated as package names by Vite and Node.\n const hasExplicitRelativePrefix =\n normalizedPath === '..' ||\n normalizedPath.startsWith('../') ||\n normalizedPath.startsWith('./');\n\n return hasExplicitRelativePrefix\n ? `${normalizedPath}/`\n : `./${normalizedPath}/`;\n}\n\nexport async function createLoadTranslationsFile(\n appDirectory: string,\n translationsDir: string = DEFAULT_TRANSLATIONS_DIR,\n locales: string[]\n) {\n const usingSrcDirectory = fs.existsSync(path.join(appDirectory, 'src'));\n\n const loadTranslationsDir = usingSrcDirectory\n ? path.join(appDirectory, 'src')\n : appDirectory;\n const relativePath = path.relative(\n loadTranslationsDir,\n path.resolve(appDirectory, translationsDir)\n );\n const publicPath = toRelativeImportPath(relativePath);\n\n const filePath = usingSrcDirectory\n ? path.join(appDirectory, 'src', 'loadTranslations.js')\n : path.join(appDirectory, 'loadTranslations.js');\n\n if (!fs.existsSync(filePath)) {\n const loadTranslationsContent = `\nexport default async function loadTranslations(locale) {\n try {\n // Load translations from ${translationsDir} directory\n // This matches the GT config files.gt.output path\n const t = await import(\\`${publicPath}\\${locale}.json\\`);\n return t.default;\n } catch (error) {\n console.warn(\\`Failed to load translations for locale \\${locale}:\\`, error);\n return {};\n }\n}\n`;\n await fs.promises.writeFile(filePath, loadTranslationsContent);\n logger.info(\n `Created ${chalk.cyan(\n 'loadTranslations.js'\n )} file at ${chalk.cyan(filePath)}.`\n );\n try {\n await fs.promises.mkdir(translationsDir, { recursive: true });\n // Create empty JSON files\n for (const locale of locales) {\n if (fs.existsSync(path.join(translationsDir, `${locale}.json`))) {\n continue;\n }\n await fs.promises.writeFile(\n path.join(translationsDir, `${locale}.json`),\n '{}'\n );\n }\n } catch (error) {\n logger.error(`Failed to create translations directory: ${error}`);\n }\n } else {\n logger.info(\n `Found ${chalk.cyan('loadTranslations.js')} file at ${chalk.cyan(\n filePath\n )}. Skipping creation...`\n );\n }\n}\n"],"mappings":";;;;;;AAMA,SAAS,qBAAqB,cAAsB;CAClD,MAAM,iBAAiB,aAAa,MAAM,KAAK,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI;AAExE,KAAI,CAAC,eACH,QAAO;AAUT,QAJE,mBAAmB,QACnB,eAAe,WAAW,MAAM,IAChC,eAAe,WAAW,KAAK,GAG7B,GAAG,eAAe,KAClB,KAAK,eAAe;;AAG1B,eAAsB,2BACpB,cACA,kBAA0B,0BAC1B,SACA;CACA,MAAM,oBAAoB,GAAG,WAAW,KAAK,KAAK,cAAc,MAAM,CAAC;CAEvE,MAAM,sBAAsB,oBACxB,KAAK,KAAK,cAAc,MAAM,GAC9B;CAKJ,MAAM,aAAa,qBAJE,KAAK,SACxB,qBACA,KAAK,QAAQ,cAAc,gBAAgB,CAEO,CAAC;CAErD,MAAM,WAAW,oBACb,KAAK,KAAK,cAAc,OAAO,sBAAsB,GACrD,KAAK,KAAK,cAAc,sBAAsB;AAElD,KAAI,CAAC,GAAG,WAAW,SAAS,EAAE;EAC5B,MAAM,0BAA0B;;;gCAGJ,gBAAgB;;+BAEjB,WAAW;;;;;;;;AAQtC,QAAM,GAAG,SAAS,UAAU,UAAU,wBAAwB;AAC9D,SAAO,KACL,WAAW,MAAM,KACf,sBACD,CAAC,WAAW,MAAM,KAAK,SAAS,CAAC,GACnC;AACD,MAAI;AACF,SAAM,GAAG,SAAS,MAAM,iBAAiB,EAAE,WAAW,MAAM,CAAC;AAE7D,QAAK,MAAM,UAAU,SAAS;AAC5B,QAAI,GAAG,WAAW,KAAK,KAAK,iBAAiB,GAAG,OAAO,OAAO,CAAC,CAC7D;AAEF,UAAM,GAAG,SAAS,UAChB,KAAK,KAAK,iBAAiB,GAAG,OAAO,OAAO,EAC5C,KACD;;WAEI,OAAO;AACd,UAAO,MAAM,4CAA4C,QAAQ;;OAGnE,QAAO,KACL,SAAS,MAAM,KAAK,sBAAsB,CAAC,WAAW,MAAM,KAC1D,SACD,CAAC,wBACH"}
1
+ {"version":3,"file":"createLoadTranslationsFile.js","names":[],"sources":["../../src/fs/createLoadTranslationsFile.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from '../console/logger.js';\nimport chalk from 'chalk';\nimport { DEFAULT_TRANSLATIONS_DIR } from '../utils/constants.js';\n\nfunction toRelativeImportPath(relativePath: string) {\n const normalizedPath = relativePath.split(path.sep).join(path.posix.sep);\n\n if (!normalizedPath) {\n return './';\n }\n\n // Dynamic imports must use explicit relative specifiers; values like\n // \"src/_gt\" are otherwise treated as package names by Vite and Node.\n const hasExplicitRelativePrefix =\n normalizedPath === '..' ||\n normalizedPath.startsWith('../') ||\n normalizedPath.startsWith('./');\n\n return hasExplicitRelativePrefix\n ? `${normalizedPath}/`\n : `./${normalizedPath}/`;\n}\n\nfunction getLoaderContent(translationsDir: string, publicPath: string) {\n return `\nexport default async function loadTranslations(locale) {\n try {\n // Load translations from ${translationsDir} directory\n // This matches the GT config files.gt.output path\n const t = await import(\\`${publicPath}\\${locale}.json\\`);\n return t.default;\n } catch (error) {\n console.warn(\\`Failed to load translations for locale \\${locale}:\\`, error);\n return {};\n }\n}\n`;\n}\n\n/**\n * Every loadTranslations file the app has, in gt-next's lookup order\n * (resolveConfigFilepath): root before src, .ts before .js. gt-next uses the\n * first one, and falls back to the next when it is deleted.\n */\nexport function findLoadTranslationsFiles(appDirectory: string): string[] {\n return ['', 'src']\n .flatMap((directory) =>\n ['.ts', '.js'].map((extension) =>\n path.join(appDirectory, directory, `loadTranslations${extension}`)\n )\n )\n .filter((candidate) => fs.existsSync(candidate));\n}\n\nexport type LoadTranslationsFileResult =\n | 'created'\n | 'updated'\n | 'unchanged'\n | 'custom';\n\n/**\n * Creates or updates the generated loadTranslations.js for translationsDir\n * (relative to appDirectory) and empty stubs for non-default locales. A\n * loader that was not matching the previous config's generated template, or\n * another loadTranslations file the app uses instead, is left untouched and\n * reported as 'custom'.\n * Directory and stub failures propagate.\n */\nexport async function createLoadTranslationsFile({\n appDirectory,\n translationsDir = DEFAULT_TRANSLATIONS_DIR,\n defaultLocale,\n locales,\n previousTranslationsDir,\n}: {\n appDirectory: string;\n translationsDir?: string;\n defaultLocale: string;\n locales: string[];\n previousTranslationsDir?: string;\n}): Promise<LoadTranslationsFileResult> {\n const usingSrcDirectory = fs.existsSync(path.join(appDirectory, 'src'));\n\n const loadTranslationsDir = usingSrcDirectory\n ? path.join(appDirectory, 'src')\n : appDirectory;\n const translationsPath = path.resolve(appDirectory, translationsDir);\n const publicPath = toRelativeImportPath(\n path.relative(loadTranslationsDir, translationsPath)\n );\n const filePath = path.join(loadTranslationsDir, 'loadTranslations.js');\n const content = getLoaderContent(translationsDir, publicPath);\n // Config paths lose leading ./ and trailing / through path.join, but\n // legacy generated comments retain them. Keep the import and body exact.\n const previousContents =\n previousTranslationsDir === undefined\n ? []\n : [\n previousTranslationsDir,\n ...(!path.isAbsolute(previousTranslationsDir)\n ? [`./${previousTranslationsDir}`]\n : []),\n ]\n .flatMap((directory) => [directory, `${directory}/`])\n .map((directory) =>\n getLoaderContent(\n directory,\n toRelativeImportPath(\n path.relative(\n loadTranslationsDir,\n path.resolve(appDirectory, previousTranslationsDir)\n )\n )\n )\n );\n\n const [loaderPath] = findLoadTranslationsFiles(appDirectory);\n const existing =\n loaderPath === filePath\n ? await fs.promises.readFile(filePath, 'utf8')\n : undefined;\n // Stubs first, so a directory failure leaves no loader pointing at it; a\n // custom loader also gets them, like the Vite loader.\n await fs.promises.mkdir(translationsPath, { recursive: true });\n for (const locale of new Set(locales)) {\n // Default-locale content lives in source, so it never needs a stub.\n if (locale === defaultLocale) continue;\n const stubPath = path.join(translationsPath, `${locale}.json`);\n if (!fs.existsSync(stubPath)) await fs.promises.writeFile(stubPath, '{}');\n }\n // Another loader wins over the generated one, so writing it would not help.\n if (\n (loaderPath !== undefined && loaderPath !== filePath) ||\n (existing !== undefined &&\n existing !== content &&\n !previousContents.includes(existing))\n ) {\n logger.info(\n `Found a custom ${chalk.cyan(\n path.basename(loaderPath ?? filePath)\n )} at ${chalk.cyan(loaderPath ?? filePath)}; leaving it unchanged.`\n );\n return 'custom';\n }\n\n if (existing === content) return 'unchanged';\n await fs.promises.writeFile(filePath, content);\n logger.info(\n `${existing === undefined ? 'Created' : 'Updated'} ${chalk.cyan(\n 'loadTranslations.js'\n )} at ${chalk.cyan(filePath)}.`\n );\n return existing === undefined ? 'created' : 'updated';\n}\n"],"mappings":";;;;;;AAMA,SAAS,qBAAqB,cAAsB;CAClD,MAAM,iBAAiB,aAAa,MAAM,KAAK,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI;AAExE,KAAI,CAAC,eACH,QAAO;AAUT,QAJE,mBAAmB,QACnB,eAAe,WAAW,MAAM,IAChC,eAAe,WAAW,KAAK,GAG7B,GAAG,eAAe,KAClB,KAAK,eAAe;;AAG1B,SAAS,iBAAiB,iBAAyB,YAAoB;AACrE,QAAO;;;gCAGuB,gBAAgB;;+BAEjB,WAAW;;;;;;;;;;;;;;AAe1C,SAAgB,0BAA0B,cAAgC;AACxE,QAAO,CAAC,IAAI,MAAM,CACf,SAAS,cACR,CAAC,OAAO,MAAM,CAAC,KAAK,cAClB,KAAK,KAAK,cAAc,WAAW,mBAAmB,YAAY,CACnE,CACF,CACA,QAAQ,cAAc,GAAG,WAAW,UAAU,CAAC;;;;;;;;;;AAiBpD,eAAsB,2BAA2B,EAC/C,cACA,kBAAkB,0BAClB,eACA,SACA,2BAOsC;CAGtC,MAAM,sBAFoB,GAAG,WAAW,KAAK,KAAK,cAAc,MAAM,CAEzB,GACzC,KAAK,KAAK,cAAc,MAAM,GAC9B;CACJ,MAAM,mBAAmB,KAAK,QAAQ,cAAc,gBAAgB;CACpE,MAAM,aAAa,qBACjB,KAAK,SAAS,qBAAqB,iBAAiB,CACrD;CACD,MAAM,WAAW,KAAK,KAAK,qBAAqB,sBAAsB;CACtE,MAAM,UAAU,iBAAiB,iBAAiB,WAAW;CAG7D,MAAM,mBACJ,4BAA4B,KAAA,IACxB,EAAE,GACF,CACE,yBACA,GAAI,CAAC,KAAK,WAAW,wBAAwB,GACzC,CAAC,KAAK,0BAA0B,GAChC,EAAE,CACP,CACE,SAAS,cAAc,CAAC,WAAW,GAAG,UAAU,GAAG,CAAC,CACpD,KAAK,cACJ,iBACE,WACA,qBACE,KAAK,SACH,qBACA,KAAK,QAAQ,cAAc,wBAAwB,CACpD,CACF,CACF,CACF;CAET,MAAM,CAAC,cAAc,0BAA0B,aAAa;CAC5D,MAAM,WACJ,eAAe,WACX,MAAM,GAAG,SAAS,SAAS,UAAU,OAAO,GAC5C,KAAA;AAGN,OAAM,GAAG,SAAS,MAAM,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAC9D,MAAK,MAAM,UAAU,IAAI,IAAI,QAAQ,EAAE;AAErC,MAAI,WAAW,cAAe;EAC9B,MAAM,WAAW,KAAK,KAAK,kBAAkB,GAAG,OAAO,OAAO;AAC9D,MAAI,CAAC,GAAG,WAAW,SAAS,CAAE,OAAM,GAAG,SAAS,UAAU,UAAU,KAAK;;AAG3E,KACG,eAAe,KAAA,KAAa,eAAe,YAC3C,aAAa,KAAA,KACZ,aAAa,WACb,CAAC,iBAAiB,SAAS,SAAS,EACtC;AACA,SAAO,KACL,kBAAkB,MAAM,KACtB,KAAK,SAAS,cAAc,SAAS,CACtC,CAAC,MAAM,MAAM,KAAK,cAAc,SAAS,CAAC,yBAC5C;AACD,SAAO;;AAGT,KAAI,aAAa,QAAS,QAAO;AACjC,OAAM,GAAG,SAAS,UAAU,UAAU,QAAQ;AAC9C,QAAO,KACL,GAAG,aAAa,KAAA,IAAY,YAAY,UAAU,GAAG,MAAM,KACzD,sBACD,CAAC,MAAM,MAAM,KAAK,SAAS,CAAC,GAC9B;AACD,QAAO,aAAa,KAAA,IAAY,YAAY"}
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.22.4";
1
+ export declare const PACKAGE_VERSION = "2.23.0";
@@ -1,5 +1,5 @@
1
1
  //#region src/generated/version.ts
2
- const PACKAGE_VERSION = "2.22.4";
2
+ const PACKAGE_VERSION = "2.23.0";
3
3
  //#endregion
4
4
  export { PACKAGE_VERSION };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","names":[],"sources":["../../src/generated/version.ts"],"sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport const PACKAGE_VERSION = '2.22.4';\n"],"mappings":";AACA,MAAa,kBAAkB"}
1
+ {"version":3,"file":"version.js","names":[],"sources":["../../src/generated/version.ts"],"sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport const PACKAGE_VERSION = '2.23.0';\n"],"mappings":";AACA,MAAa,kBAAkB"}
@@ -1,4 +1,3 @@
1
- type Formatter = 'prettier' | 'biome' | 'eslint';
1
+ export type Formatter = 'prettier' | 'biome' | 'eslint';
2
2
  export declare function detectFormatter(): Promise<Formatter | null>;
3
3
  export declare function formatFiles(filesUpdated: string[], formatter?: Formatter): Promise<void>;
4
- export {};
@@ -59,7 +59,7 @@ async function formatFiles(filesUpdated, formatter) {
59
59
  ...filesUpdated.map((file) => file)
60
60
  ], { stdio: [
61
61
  "ignore",
62
- "inherit",
62
+ process.stderr,
63
63
  "inherit"
64
64
  ] });
65
65
  child.on("error", (error) => {
@@ -1 +1 @@
1
- {"version":3,"file":"postProcess.js","names":[],"sources":["../../src/hooks/postProcess.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { spawn } from 'node:child_process';\nimport chalk from 'chalk';\nimport { logger } from '../console/logger.js';\n\ntype Formatter = 'prettier' | 'biome' | 'eslint';\n\nexport async function detectFormatter(): Promise<Formatter | null> {\n // Try Prettier\n try {\n await import('prettier');\n return 'prettier';\n } catch {\n // Prettier is optional.\n }\n\n // Try ESLint\n try {\n await import('eslint');\n return 'eslint';\n } catch {\n // ESLint is optional.\n }\n\n // Try Biome\n try {\n return await new Promise<Formatter | null>((resolve) => {\n const child = spawn('npx', ['@biomejs/biome', '--version'], {\n stdio: 'ignore',\n });\n\n child.on('error', () => {\n resolve(null);\n });\n\n child.on('close', (code: number) => {\n if (code === 0) {\n resolve('biome');\n } else {\n resolve(null);\n }\n });\n });\n } catch {\n // Biome is optional.\n }\n\n return null;\n}\n\nexport async function formatFiles(\n filesUpdated: string[],\n formatter?: Formatter\n): Promise<void> {\n if (filesUpdated.length === 0) return;\n\n try {\n const detectedFormatter = formatter || (await detectFormatter());\n\n if (!detectedFormatter) {\n logger.warn(chalk.yellow('No supported formatter detected'));\n return;\n }\n\n if (detectedFormatter === 'prettier') {\n logger.message(chalk.dim('Cleaning up with prettier...'));\n const prettier = await import('prettier');\n for (const file of filesUpdated) {\n const config = await prettier.resolveConfig(file);\n const content = await fs.promises.readFile(file, 'utf-8');\n const formatted = await prettier.format(content, {\n ...config,\n filepath: file,\n });\n await fs.promises.writeFile(file, formatted);\n }\n return;\n }\n\n if (detectedFormatter === 'biome') {\n logger.message(chalk.dim('Cleaning up with biome...'));\n try {\n await new Promise<void>((resolve) => {\n const args = [\n '@biomejs/biome',\n 'format',\n '--write',\n ...filesUpdated.map((file) => file),\n ];\n\n const child = spawn('npx', args, {\n stdio: ['ignore', 'inherit', 'inherit'],\n });\n\n child.on('error', (error: Error) => {\n logger.warn(\n chalk.yellow('Biome formatting failed: ' + error.message)\n );\n resolve();\n });\n\n child.on('close', (code: number) => {\n if (code !== 0) {\n logger.warn(\n chalk.yellow(`Biome formatting failed with exit code ${code}`)\n );\n }\n resolve();\n });\n });\n } catch (error) {\n logger.warn(chalk.yellow('Biome formatting failed: ' + String(error)));\n }\n return;\n }\n\n if (detectedFormatter === 'eslint') {\n logger.message(chalk.dim('Cleaning up with eslint...'));\n const { ESLint } = await import('eslint');\n const eslint = new ESLint({\n fix: true,\n overrideConfigFile: undefined, // Will use project's .eslintrc\n });\n for (const file of filesUpdated) {\n const results = await eslint.lintFiles([file]);\n await ESLint.outputFixes(results);\n }\n return;\n }\n } catch (e) {\n logger.warn(chalk.yellow('Unable to run code formatter: ' + String(e)));\n }\n}\n"],"mappings":";;;;;AAOA,eAAsB,kBAA6C;AAEjE,KAAI;AACF,QAAM,OAAO;AACb,SAAO;SACD;AAKR,KAAI;AACF,QAAM,OAAO;AACb,SAAO;SACD;AAKR,KAAI;AACF,SAAO,MAAM,IAAI,SAA2B,YAAY;GACtD,MAAM,QAAQ,MAAM,OAAO,CAAC,kBAAkB,YAAY,EAAE,EAC1D,OAAO,UACR,CAAC;AAEF,SAAM,GAAG,eAAe;AACtB,YAAQ,KAAK;KACb;AAEF,SAAM,GAAG,UAAU,SAAiB;AAClC,QAAI,SAAS,EACX,SAAQ,QAAQ;QAEhB,SAAQ,KAAK;KAEf;IACF;SACI;AAIR,QAAO;;AAGT,eAAsB,YACpB,cACA,WACe;AACf,KAAI,aAAa,WAAW,EAAG;AAE/B,KAAI;EACF,MAAM,oBAAoB,aAAc,MAAM,iBAAiB;AAE/D,MAAI,CAAC,mBAAmB;AACtB,UAAO,KAAK,MAAM,OAAO,kCAAkC,CAAC;AAC5D;;AAGF,MAAI,sBAAsB,YAAY;AACpC,UAAO,QAAQ,MAAM,IAAI,+BAA+B,CAAC;GACzD,MAAM,WAAW,MAAM,OAAO;AAC9B,QAAK,MAAM,QAAQ,cAAc;IAC/B,MAAM,SAAS,MAAM,SAAS,cAAc,KAAK;IACjD,MAAM,UAAU,MAAM,GAAG,SAAS,SAAS,MAAM,QAAQ;IACzD,MAAM,YAAY,MAAM,SAAS,OAAO,SAAS;KAC/C,GAAG;KACH,UAAU;KACX,CAAC;AACF,UAAM,GAAG,SAAS,UAAU,MAAM,UAAU;;AAE9C;;AAGF,MAAI,sBAAsB,SAAS;AACjC,UAAO,QAAQ,MAAM,IAAI,4BAA4B,CAAC;AACtD,OAAI;AACF,UAAM,IAAI,SAAe,YAAY;KAQnC,MAAM,QAAQ,MAAM,OAAO;MANzB;MACA;MACA;MACA,GAAG,aAAa,KAAK,SAAS,KAAK;MAGN,EAAE,EAC/B,OAAO;MAAC;MAAU;MAAW;MAAU,EACxC,CAAC;AAEF,WAAM,GAAG,UAAU,UAAiB;AAClC,aAAO,KACL,MAAM,OAAO,8BAA8B,MAAM,QAAQ,CAC1D;AACD,eAAS;OACT;AAEF,WAAM,GAAG,UAAU,SAAiB;AAClC,UAAI,SAAS,EACX,QAAO,KACL,MAAM,OAAO,0CAA0C,OAAO,CAC/D;AAEH,eAAS;OACT;MACF;YACK,OAAO;AACd,WAAO,KAAK,MAAM,OAAO,8BAA8B,OAAO,MAAM,CAAC,CAAC;;AAExE;;AAGF,MAAI,sBAAsB,UAAU;AAClC,UAAO,QAAQ,MAAM,IAAI,6BAA6B,CAAC;GACvD,MAAM,EAAE,WAAW,MAAM,OAAO;GAChC,MAAM,SAAS,IAAI,OAAO;IACxB,KAAK;IACL,oBAAoB,KAAA;IACrB,CAAC;AACF,QAAK,MAAM,QAAQ,cAAc;IAC/B,MAAM,UAAU,MAAM,OAAO,UAAU,CAAC,KAAK,CAAC;AAC9C,UAAM,OAAO,YAAY,QAAQ;;AAEnC;;UAEK,GAAG;AACV,SAAO,KAAK,MAAM,OAAO,mCAAmC,OAAO,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"postProcess.js","names":[],"sources":["../../src/hooks/postProcess.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { spawn } from 'node:child_process';\nimport chalk from 'chalk';\nimport { logger } from '../console/logger.js';\n\nexport type Formatter = 'prettier' | 'biome' | 'eslint';\n\nexport async function detectFormatter(): Promise<Formatter | null> {\n // Try Prettier\n try {\n await import('prettier');\n return 'prettier';\n } catch {\n // Prettier is optional.\n }\n\n // Try ESLint\n try {\n await import('eslint');\n return 'eslint';\n } catch {\n // ESLint is optional.\n }\n\n // Try Biome\n try {\n return await new Promise<Formatter | null>((resolve) => {\n const child = spawn('npx', ['@biomejs/biome', '--version'], {\n stdio: 'ignore',\n });\n\n child.on('error', () => {\n resolve(null);\n });\n\n child.on('close', (code: number) => {\n if (code === 0) {\n resolve('biome');\n } else {\n resolve(null);\n }\n });\n });\n } catch {\n // Biome is optional.\n }\n\n return null;\n}\n\nexport async function formatFiles(\n filesUpdated: string[],\n formatter?: Formatter\n): Promise<void> {\n if (filesUpdated.length === 0) return;\n\n try {\n const detectedFormatter = formatter || (await detectFormatter());\n\n if (!detectedFormatter) {\n logger.warn(chalk.yellow('No supported formatter detected'));\n return;\n }\n\n if (detectedFormatter === 'prettier') {\n logger.message(chalk.dim('Cleaning up with prettier...'));\n const prettier = await import('prettier');\n for (const file of filesUpdated) {\n const config = await prettier.resolveConfig(file);\n const content = await fs.promises.readFile(file, 'utf-8');\n const formatted = await prettier.format(content, {\n ...config,\n filepath: file,\n });\n await fs.promises.writeFile(file, formatted);\n }\n return;\n }\n\n if (detectedFormatter === 'biome') {\n logger.message(chalk.dim('Cleaning up with biome...'));\n try {\n await new Promise<void>((resolve) => {\n const args = [\n '@biomejs/biome',\n 'format',\n '--write',\n ...filesUpdated.map((file) => file),\n ];\n\n // Formatter output is diagnostics; keep stdout free for commands' data.\n const child = spawn('npx', args, {\n stdio: ['ignore', process.stderr, 'inherit'],\n });\n\n child.on('error', (error: Error) => {\n logger.warn(\n chalk.yellow('Biome formatting failed: ' + error.message)\n );\n resolve();\n });\n\n child.on('close', (code: number) => {\n if (code !== 0) {\n logger.warn(\n chalk.yellow(`Biome formatting failed with exit code ${code}`)\n );\n }\n resolve();\n });\n });\n } catch (error) {\n logger.warn(chalk.yellow('Biome formatting failed: ' + String(error)));\n }\n return;\n }\n\n if (detectedFormatter === 'eslint') {\n logger.message(chalk.dim('Cleaning up with eslint...'));\n const { ESLint } = await import('eslint');\n const eslint = new ESLint({\n fix: true,\n overrideConfigFile: undefined, // Will use project's .eslintrc\n });\n for (const file of filesUpdated) {\n const results = await eslint.lintFiles([file]);\n await ESLint.outputFixes(results);\n }\n return;\n }\n } catch (e) {\n logger.warn(chalk.yellow('Unable to run code formatter: ' + String(e)));\n }\n}\n"],"mappings":";;;;;AAOA,eAAsB,kBAA6C;AAEjE,KAAI;AACF,QAAM,OAAO;AACb,SAAO;SACD;AAKR,KAAI;AACF,QAAM,OAAO;AACb,SAAO;SACD;AAKR,KAAI;AACF,SAAO,MAAM,IAAI,SAA2B,YAAY;GACtD,MAAM,QAAQ,MAAM,OAAO,CAAC,kBAAkB,YAAY,EAAE,EAC1D,OAAO,UACR,CAAC;AAEF,SAAM,GAAG,eAAe;AACtB,YAAQ,KAAK;KACb;AAEF,SAAM,GAAG,UAAU,SAAiB;AAClC,QAAI,SAAS,EACX,SAAQ,QAAQ;QAEhB,SAAQ,KAAK;KAEf;IACF;SACI;AAIR,QAAO;;AAGT,eAAsB,YACpB,cACA,WACe;AACf,KAAI,aAAa,WAAW,EAAG;AAE/B,KAAI;EACF,MAAM,oBAAoB,aAAc,MAAM,iBAAiB;AAE/D,MAAI,CAAC,mBAAmB;AACtB,UAAO,KAAK,MAAM,OAAO,kCAAkC,CAAC;AAC5D;;AAGF,MAAI,sBAAsB,YAAY;AACpC,UAAO,QAAQ,MAAM,IAAI,+BAA+B,CAAC;GACzD,MAAM,WAAW,MAAM,OAAO;AAC9B,QAAK,MAAM,QAAQ,cAAc;IAC/B,MAAM,SAAS,MAAM,SAAS,cAAc,KAAK;IACjD,MAAM,UAAU,MAAM,GAAG,SAAS,SAAS,MAAM,QAAQ;IACzD,MAAM,YAAY,MAAM,SAAS,OAAO,SAAS;KAC/C,GAAG;KACH,UAAU;KACX,CAAC;AACF,UAAM,GAAG,SAAS,UAAU,MAAM,UAAU;;AAE9C;;AAGF,MAAI,sBAAsB,SAAS;AACjC,UAAO,QAAQ,MAAM,IAAI,4BAA4B,CAAC;AACtD,OAAI;AACF,UAAM,IAAI,SAAe,YAAY;KASnC,MAAM,QAAQ,MAAM,OAAO;MAPzB;MACA;MACA;MACA,GAAG,aAAa,KAAK,SAAS,KAAK;MAIN,EAAE,EAC/B,OAAO;MAAC;MAAU,QAAQ;MAAQ;MAAU,EAC7C,CAAC;AAEF,WAAM,GAAG,UAAU,UAAiB;AAClC,aAAO,KACL,MAAM,OAAO,8BAA8B,MAAM,QAAQ,CAC1D;AACD,eAAS;OACT;AAEF,WAAM,GAAG,UAAU,SAAiB;AAClC,UAAI,SAAS,EACX,QAAO,KACL,MAAM,OAAO,0CAA0C,OAAO,CAC/D;AAEH,eAAS;OACT;MACF;YACK,OAAO;AACd,WAAO,KAAK,MAAM,OAAO,8BAA8B,OAAO,MAAM,CAAC,CAAC;;AAExE;;AAGF,MAAI,sBAAsB,UAAU;AAClC,UAAO,QAAQ,MAAM,IAAI,6BAA6B,CAAC;GACvD,MAAM,EAAE,WAAW,MAAM,OAAO;GAChC,MAAM,SAAS,IAAI,OAAO;IACxB,KAAK;IACL,oBAAoB,KAAA;IACrB,CAAC;AACF,QAAK,MAAM,QAAQ,cAAc;IAC/B,MAAM,UAAU,MAAM,OAAO,UAAU,CAAC,KAAK,CAAC;AAC9C,UAAM,OAAO,YAAY,QAAQ;;AAEnC;;UAEK,GAAG;AACV,SAAO,KAAK,MAAM,OAAO,mCAAmC,OAAO,EAAE,CAAC,CAAC"}
@@ -1,2 +1,5 @@
1
1
  import { Settings } from '../types/index.js';
2
- export declare function setupLocadex(settings: Settings): Promise<void>;
2
+ /** Opens the GitHub connection page unless the caller only hands off the URL. */
3
+ export declare function setupLocadex(settings: Settings, { openBrowser }?: {
4
+ openBrowser?: boolean;
5
+ }): Promise<string>;
@@ -1,10 +1,12 @@
1
1
  import { logger } from "../console/logger.js";
2
2
  import chalk from "chalk";
3
3
  //#region src/locadex/setupFlow.ts
4
- async function setupLocadex(settings) {
4
+ /** Opens the GitHub connection page unless the caller only hands off the URL. */
5
+ async function setupLocadex(settings, { openBrowser = true } = {}) {
5
6
  const urlToOpen = `${settings.dashboardUrl}/api/integrations/github/start?returnTo=%2Fproject%2Flocadex`;
6
- await import("open").then((open) => open.default(urlToOpen, { wait: false }));
7
- logger.message(`${chalk.dim(`If the browser window didn't open automatically, open the following link:`)}\n\n${chalk.cyan(urlToOpen)}`);
7
+ if (openBrowser) await import("open").then((open) => open.default(urlToOpen, { wait: false }));
8
+ logger.message(`${chalk.dim(openBrowser ? `If the browser window didn't open automatically, open the following link:` : "Open the following link to connect GitHub and finish setting up Locadex:")}\n\n${chalk.cyan(urlToOpen)}`);
9
+ return urlToOpen;
8
10
  }
9
11
  //#endregion
10
12
  export { setupLocadex };
@@ -1 +1 @@
1
- {"version":3,"file":"setupFlow.js","names":[],"sources":["../../src/locadex/setupFlow.ts"],"sourcesContent":["import { Settings } from '../types/index.js';\nimport { logger } from '../console/logger.js';\nimport chalk from 'chalk';\n\nexport async function setupLocadex(settings: Settings): Promise<void> {\n const urlToOpen = `${settings.dashboardUrl}/api/integrations/github/start?returnTo=%2Fproject%2Flocadex`;\n await import('open').then((open) =>\n open.default(urlToOpen, {\n wait: false,\n })\n );\n\n logger.message(\n `${chalk.dim(\n `If the browser window didn't open automatically, open the following link:`\n )}\\n\\n${chalk.cyan(urlToOpen)}`\n );\n}\n"],"mappings":";;;AAIA,eAAsB,aAAa,UAAmC;CACpE,MAAM,YAAY,GAAG,SAAS,aAAa;AAC3C,OAAM,OAAO,QAAQ,MAAM,SACzB,KAAK,QAAQ,WAAW,EACtB,MAAM,OACP,CAAC,CACH;AAED,QAAO,QACL,GAAG,MAAM,IACP,4EACD,CAAC,MAAM,MAAM,KAAK,UAAU,GAC9B"}
1
+ {"version":3,"file":"setupFlow.js","names":[],"sources":["../../src/locadex/setupFlow.ts"],"sourcesContent":["import { Settings } from '../types/index.js';\nimport { logger } from '../console/logger.js';\nimport chalk from 'chalk';\n\n/** Opens the GitHub connection page unless the caller only hands off the URL. */\nexport async function setupLocadex(\n settings: Settings,\n { openBrowser = true }: { openBrowser?: boolean } = {}\n): Promise<string> {\n const urlToOpen = `${settings.dashboardUrl}/api/integrations/github/start?returnTo=%2Fproject%2Flocadex`;\n if (openBrowser) {\n await import('open').then((open) =>\n open.default(urlToOpen, {\n wait: false,\n })\n );\n }\n\n logger.message(\n `${chalk.dim(\n openBrowser\n ? `If the browser window didn't open automatically, open the following link:`\n : 'Open the following link to connect GitHub and finish setting up Locadex:'\n )}\\n\\n${chalk.cyan(urlToOpen)}`\n );\n return urlToOpen;\n}\n"],"mappings":";;;;AAKA,eAAsB,aACpB,UACA,EAAE,cAAc,SAAoC,EAAE,EACrC;CACjB,MAAM,YAAY,GAAG,SAAS,aAAa;AAC3C,KAAI,YACF,OAAM,OAAO,QAAQ,MAAM,SACzB,KAAK,QAAQ,WAAW,EACtB,MAAM,OACP,CAAC,CACH;AAGH,QAAO,QACL,GAAG,MAAM,IACP,cACI,8EACA,2EACL,CAAC,MAAM,MAAM,KAAK,UAAU,GAC9B;AACD,QAAO"}
@@ -1,7 +1,7 @@
1
1
  import { DATA_ATTR_PREFIX } from "../constants.js";
2
2
  import { defaultVariableNames, getVariableName, minifyVariableType } from "../../../utils/getVariableName.js";
3
- import { HTML_CONTENT_PROPS } from "@generaltranslation/format/types";
4
3
  import { isAcceptedPluralForm } from "generaltranslation/internal";
4
+ import { HTML_CONTENT_PROPS } from "@generaltranslation/format/types";
5
5
  //#region src/react/jsx/utils/jsxParsing/addGTIdentifierToSyntaxTree.ts
6
6
  /**
7
7
  * Construct the data-_gt prop
@@ -15,6 +15,7 @@ import { autoInsertJsxComponents, ensureTAndVarImported } from "./autoInsertion.
15
15
  import { extractSourceCode } from "../extractSourceCode.js";
16
16
  import { nodeToStrings, parseStringExpression } from "../parseString.js";
17
17
  import { handleDerivation } from "../stringParsing/derivation/handleDerivation.js";
18
+ import { isAcceptedPluralForm } from "generaltranslation/internal";
18
19
  import { randomUUID } from "node:crypto";
19
20
  import path from "node:path";
20
21
  import fs from "node:fs";
@@ -22,7 +23,6 @@ import * as t from "@babel/types";
22
23
  import { parse } from "@babel/parser";
23
24
  import generateModule from "@babel/generator";
24
25
  import { HTML_CONTENT_PROPS } from "@generaltranslation/format/types";
25
- import { isAcceptedPluralForm } from "generaltranslation/internal";
26
26
  import traverseModule from "@babel/traverse";
27
27
  //#region src/react/jsx/utils/jsxParsing/parseJsx.ts
28
28
  const generate = generateModule.default || generateModule;
@@ -4,11 +4,11 @@ import "./constants.js";
4
4
  import { warnDeriveCircularSpreadSync, warnDeriveDestructuringSync, warnDeriveFunctionNoResultsSync, warnDeriveNonConstVariableSync, warnDeriveOptionalChainingSync, warnDeriveUnresolvableValueSync, warnFunctionNotFoundSync, warnInvalidDeclareVarNameSync } from "../../../console/index.js";
5
5
  import { resolveImportPath } from "./resolveImportPath.js";
6
6
  import { buildImportMap } from "./buildImportMap.js";
7
+ import { declareVar } from "generaltranslation/internal";
7
8
  import fs from "node:fs";
8
9
  import * as t from "@babel/types";
9
10
  import { parse } from "@babel/parser";
10
11
  import generateModule from "@babel/generator";
11
- import { declareVar } from "generaltranslation/internal";
12
12
  import traverseModule from "@babel/traverse";
13
13
  //#region src/react/jsx/utils/parseString.ts
14
14
  const traverse = traverseModule.default || traverseModule;
@@ -2,9 +2,9 @@ import { isValidIcu } from "../../../evaluateJsx.js";
2
2
  import { warnInvalidIcuSync, warnNonStringSync } from "../../../../../console/index.js";
3
3
  import { nodeToStrings } from "../../parseString.js";
4
4
  import { handleDerivation } from "./handleDerivation.js";
5
+ import { indexVars } from "generaltranslation/internal";
5
6
  import { randomUUID } from "node:crypto";
6
7
  import generateModule from "@babel/generator";
7
- import { indexVars } from "generaltranslation/internal";
8
8
  //#region src/react/jsx/utils/stringParsing/derivation/index.ts
9
9
  const generate = generateModule.default || generateModule;
10
10
  /**
@@ -0,0 +1,44 @@
1
+ import type { SupportedReactFrameworks } from '../../types/index.js';
2
+ /** A change setup left to a person, reported as a warning. */
3
+ export type ManualAction = {
4
+ whatHappened: string;
5
+ fix: string;
6
+ };
7
+ /** What a build-tool hook changed, and what a person still has to do. */
8
+ export type SetupResult = {
9
+ steps: string[];
10
+ manualActions: ManualAction[];
11
+ };
12
+ export type BuildToolContext = {
13
+ appDirectory: string;
14
+ configFilepath: string;
15
+ defaultLocale: string;
16
+ locales: string[];
17
+ /** Set when translations are stored locally. */
18
+ translationsDir?: string;
19
+ /** The translations directory in the existing config. */
20
+ previousTranslationsDir?: string;
21
+ };
22
+ /** Setup steps for a build tool whose app entry GT configures itself. */
23
+ export type BuildToolSetup = {
24
+ framework: SupportedReactFrameworks;
25
+ defaultTranslationsDir: string;
26
+ /** The runtime entry named in the defaults text. */
27
+ initializer: string;
28
+ /** Loads local translations itself instead of loadTranslations.js. */
29
+ ownsLoader: boolean;
30
+ skipsGTInstall(isUsingGT: boolean): boolean;
31
+ /** The development credentials question asked with local storage. */
32
+ devCredentialsOption: '--live-translations' | '--dev-credentials';
33
+ /** Rejects an app layout it cannot configure, before any change. */
34
+ preflight(appDirectory: string): Promise<void>;
35
+ /** Keeps an existing loader in sync when the React setup is skipped. */
36
+ syncLoader(ctx: BuildToolContext & {
37
+ translationsDir: string;
38
+ keepAppSource?: boolean;
39
+ }): Promise<SetupResult>;
40
+ /** Configures the app entry after gt.config.json is written. */
41
+ apply(ctx: BuildToolContext): Promise<SetupResult>;
42
+ };
43
+ export declare const BUILD_TOOL_SETUPS: BuildToolSetup[];
44
+ export declare function getBuildToolSetup(framework?: string): BuildToolSetup | undefined;
@@ -0,0 +1,10 @@
1
+ import { viteSetup } from "./vite.js";
2
+ //#region src/setup/buildTools/index.ts
3
+ const BUILD_TOOL_SETUPS = [viteSetup];
4
+ function getBuildToolSetup(framework) {
5
+ return BUILD_TOOL_SETUPS.find((setup) => setup.framework === framework);
6
+ }
7
+ //#endregion
8
+ export { BUILD_TOOL_SETUPS, getBuildToolSetup };
9
+
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/setup/buildTools/index.ts"],"sourcesContent":["import type { SupportedReactFrameworks } from '../../types/index.js';\nimport { viteSetup } from './vite.js';\n\n/** A change setup left to a person, reported as a warning. */\nexport type ManualAction = { whatHappened: string; fix: string };\n\n/** What a build-tool hook changed, and what a person still has to do. */\nexport type SetupResult = { steps: string[]; manualActions: ManualAction[] };\n\nexport type BuildToolContext = {\n appDirectory: string;\n configFilepath: string;\n defaultLocale: string;\n locales: string[];\n /** Set when translations are stored locally. */\n translationsDir?: string;\n /** The translations directory in the existing config. */\n previousTranslationsDir?: string;\n};\n\n/** Setup steps for a build tool whose app entry GT configures itself. */\nexport type BuildToolSetup = {\n framework: SupportedReactFrameworks;\n defaultTranslationsDir: string;\n /** The runtime entry named in the defaults text. */\n initializer: string;\n /** Loads local translations itself instead of loadTranslations.js. */\n ownsLoader: boolean;\n skipsGTInstall(isUsingGT: boolean): boolean;\n /** The development credentials question asked with local storage. */\n devCredentialsOption: '--live-translations' | '--dev-credentials';\n /** Rejects an app layout it cannot configure, before any change. */\n preflight(appDirectory: string): Promise<void>;\n /** Keeps an existing loader in sync when the React setup is skipped. */\n syncLoader(\n ctx: BuildToolContext & { translationsDir: string; keepAppSource?: boolean }\n ): Promise<SetupResult>;\n /** Configures the app entry after gt.config.json is written. */\n apply(ctx: BuildToolContext): Promise<SetupResult>;\n};\n\nexport const BUILD_TOOL_SETUPS: BuildToolSetup[] = [viteSetup];\n\nexport function getBuildToolSetup(\n framework?: string\n): BuildToolSetup | undefined {\n return BUILD_TOOL_SETUPS.find((setup) => setup.framework === framework);\n}\n"],"mappings":";;AAyCA,MAAa,oBAAsC,CAAC,UAAU;AAE9D,SAAgB,kBACd,WAC4B;AAC5B,QAAO,kBAAkB,MAAM,UAAU,MAAM,cAAc,UAAU"}
@@ -0,0 +1,2 @@
1
+ import type { BuildToolSetup } from './index.js';
2
+ export declare const viteSetup: BuildToolSetup;
@@ -0,0 +1,61 @@
1
+ import { DEFAULT_VITE_TRANSLATIONS_DIR } from "../../utils/constants.js";
2
+ import { inspectViteSPA, setupViteSPA, writeViteLoader } from "../setupViteSPA.js";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ //#region src/setup/buildTools/vite.ts
6
+ const VITE_LOADER_FILE = "src/loadTranslations.ts";
7
+ /** A loader left unchanged may not read the newly chosen directory. */
8
+ function loaderUpdateActions(translationsDir, previousTranslationsDir, custom) {
9
+ if (translationsDir === previousTranslationsDir) return [];
10
+ const fix = `Update ${custom ? "your custom " : ""}${VITE_LOADER_FILE} to load translations from ${translationsDir}`;
11
+ return [{
12
+ whatHappened: custom ? `Your custom ${VITE_LOADER_FILE} was left unchanged, but translations now go to ${translationsDir}` : `${VITE_LOADER_FILE} was left unchanged because the React setup was skipped, but translations now go to ${translationsDir}`,
13
+ fix
14
+ }];
15
+ }
16
+ const viteSetup = {
17
+ framework: "vite",
18
+ defaultTranslationsDir: DEFAULT_VITE_TRANSLATIONS_DIR,
19
+ initializer: "initializeGTSPA",
20
+ ownsLoader: true,
21
+ skipsGTInstall: (isUsingGT) => isUsingGT,
22
+ devCredentialsOption: "--live-translations",
23
+ async preflight(appDirectory) {
24
+ await inspectViteSPA(appDirectory);
25
+ },
26
+ async syncLoader({ appDirectory, defaultLocale, locales, translationsDir, previousTranslationsDir, keepAppSource }) {
27
+ if (keepAppSource) return {
28
+ steps: [],
29
+ manualActions: fs.existsSync(path.join(appDirectory, VITE_LOADER_FILE)) ? loaderUpdateActions(translationsDir, previousTranslationsDir, false) : []
30
+ };
31
+ const loader = await writeViteLoader({
32
+ appDirectory,
33
+ defaultLocale,
34
+ locales,
35
+ translationsDir,
36
+ previousTranslationsDir,
37
+ create: false
38
+ });
39
+ return {
40
+ steps: loader === "written" ? [`updated ${VITE_LOADER_FILE}`] : [],
41
+ manualActions: loader === "custom" ? loaderUpdateActions(translationsDir, previousTranslationsDir, true) : []
42
+ };
43
+ },
44
+ async apply(ctx) {
45
+ const { manualAction } = await setupViteSPA(ctx);
46
+ return manualAction ? {
47
+ steps: [],
48
+ manualActions: [{
49
+ whatHappened: "The existing Vite setup needs a manual review",
50
+ fix: manualAction
51
+ }]
52
+ } : {
53
+ steps: ["configured initializeGTSPA"],
54
+ manualActions: []
55
+ };
56
+ }
57
+ };
58
+ //#endregion
59
+ export { viteSetup };
60
+
61
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../../../src/setup/buildTools/vite.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { DEFAULT_VITE_TRANSLATIONS_DIR } from '../../utils/constants.js';\nimport {\n inspectViteSPA,\n setupViteSPA,\n writeViteLoader,\n} from '../setupViteSPA.js';\nimport type { BuildToolSetup, ManualAction } from './index.js';\n\nconst VITE_LOADER_FILE = 'src/loadTranslations.ts';\n\n/** A loader left unchanged may not read the newly chosen directory. */\nfunction loaderUpdateActions(\n translationsDir: string,\n previousTranslationsDir: string | undefined,\n custom: boolean\n): ManualAction[] {\n if (translationsDir === previousTranslationsDir) return [];\n const fix = `Update ${custom ? 'your custom ' : ''}${VITE_LOADER_FILE} to load translations from ${translationsDir}`;\n return [\n {\n whatHappened: custom\n ? `Your custom ${VITE_LOADER_FILE} was left unchanged, but translations now go to ${translationsDir}`\n : `${VITE_LOADER_FILE} was left unchanged because the React setup was skipped, but translations now go to ${translationsDir}`,\n fix,\n },\n ];\n}\n\nexport const viteSetup: BuildToolSetup = {\n framework: 'vite',\n defaultTranslationsDir: DEFAULT_VITE_TRANSLATIONS_DIR,\n initializer: 'initializeGTSPA',\n ownsLoader: true,\n skipsGTInstall: (isUsingGT) => isUsingGT,\n devCredentialsOption: '--live-translations',\n async preflight(appDirectory) {\n await inspectViteSPA(appDirectory);\n },\n // Configure keeps an existing loader in sync; init leaves application\n // source to the person.\n async syncLoader({\n appDirectory,\n defaultLocale,\n locales,\n translationsDir,\n previousTranslationsDir,\n keepAppSource,\n }) {\n if (keepAppSource) {\n return {\n steps: [],\n manualActions: fs.existsSync(path.join(appDirectory, VITE_LOADER_FILE))\n ? loaderUpdateActions(translationsDir, previousTranslationsDir, false)\n : [],\n };\n }\n const loader = await writeViteLoader({\n appDirectory,\n defaultLocale,\n locales,\n translationsDir,\n previousTranslationsDir,\n create: false,\n });\n return {\n steps: loader === 'written' ? [`updated ${VITE_LOADER_FILE}`] : [],\n manualActions:\n loader === 'custom'\n ? loaderUpdateActions(translationsDir, previousTranslationsDir, true)\n : [],\n };\n },\n async apply(ctx) {\n const { manualAction } = await setupViteSPA(ctx);\n return manualAction\n ? {\n steps: [],\n manualActions: [\n {\n whatHappened: 'The existing Vite setup needs a manual review',\n fix: manualAction,\n },\n ],\n }\n : { steps: ['configured initializeGTSPA'], manualActions: [] };\n },\n};\n"],"mappings":";;;;;AAUA,MAAM,mBAAmB;;AAGzB,SAAS,oBACP,iBACA,yBACA,QACgB;AAChB,KAAI,oBAAoB,wBAAyB,QAAO,EAAE;CAC1D,MAAM,MAAM,UAAU,SAAS,iBAAiB,KAAK,iBAAiB,6BAA6B;AACnG,QAAO,CACL;EACE,cAAc,SACV,eAAe,iBAAiB,kDAAkD,oBAClF,GAAG,iBAAiB,sFAAsF;EAC9G;EACD,CACF;;AAGH,MAAa,YAA4B;CACvC,WAAW;CACX,wBAAwB;CACxB,aAAa;CACb,YAAY;CACZ,iBAAiB,cAAc;CAC/B,sBAAsB;CACtB,MAAM,UAAU,cAAc;AAC5B,QAAM,eAAe,aAAa;;CAIpC,MAAM,WAAW,EACf,cACA,eACA,SACA,iBACA,yBACA,iBACC;AACD,MAAI,cACF,QAAO;GACL,OAAO,EAAE;GACT,eAAe,GAAG,WAAW,KAAK,KAAK,cAAc,iBAAiB,CAAC,GACnE,oBAAoB,iBAAiB,yBAAyB,MAAM,GACpE,EAAE;GACP;EAEH,MAAM,SAAS,MAAM,gBAAgB;GACnC;GACA;GACA;GACA;GACA;GACA,QAAQ;GACT,CAAC;AACF,SAAO;GACL,OAAO,WAAW,YAAY,CAAC,WAAW,mBAAmB,GAAG,EAAE;GAClE,eACE,WAAW,WACP,oBAAoB,iBAAiB,yBAAyB,KAAK,GACnE,EAAE;GACT;;CAEH,MAAM,MAAM,KAAK;EACf,MAAM,EAAE,iBAAiB,MAAM,aAAa,IAAI;AAChD,SAAO,eACH;GACE,OAAO,EAAE;GACT,eAAe,CACb;IACE,cAAc;IACd,KAAK;IACN,CACF;GACF,GACD;GAAE,OAAO,CAAC,6BAA6B;GAAE,eAAe,EAAE;GAAE;;CAEnE"}
@@ -1,8 +1,43 @@
1
1
  import type { Settings, SupportedFrameworks } from '../types/index.js';
2
+ import { type OnboardingSession } from './onboarding.js';
3
+ /** .env.local never reaches production; the runtime key there is set on the host. */
4
+ export declare function productionRuntimeKeyGuidance(dashboardUrl: string): string;
2
5
  /**
3
- * Picks or creates the project, mints a development key limited to runtime
4
- * translation, and saves both to .env.local. The file is checked before any
5
- * key exists, every service call completes before anything is written, and
6
- * the key is never printed.
6
+ * Interactive setup keeps the browser login with its device fallback;
7
+ * noninteractive setup always shows a device code (and emits it as a JSON
8
+ * event) and waits for a person to approve it, without opening a browser.
7
9
  */
8
- export declare function provisionDevelopmentCredentials(settings: Settings, framework: SupportedFrameworks | undefined, cwd?: string): Promise<void>;
10
+ export declare function signInForSetup(session: OnboardingSession, baseUrl: string | undefined): Promise<void>;
11
+ /** An existing project, or the inputs for creating one. */
12
+ export type DevelopmentProject = {
13
+ id: string;
14
+ } | {
15
+ create: {
16
+ orgId: string;
17
+ name: string;
18
+ };
19
+ };
20
+ export type DevelopmentProjectOptions = {
21
+ createProject?: boolean;
22
+ orgId?: string;
23
+ projectName?: string;
24
+ };
25
+ /**
26
+ * Records project inputs a noninteractive run is missing, before signing in,
27
+ * so it never waits for approval only to fail on a missing flag.
28
+ */
29
+ export declare function checkDevelopmentProjectInputs(session: OnboardingSession, settings: Settings, options: DevelopmentProjectOptions,
30
+ /** Where settings.projectId came from, so a person can remove it. */
31
+ projectIdSource: string): void;
32
+ /**
33
+ * Chooses the project for development credentials without creating anything:
34
+ * a supplied or configured ID, explicit creation inputs, or (interactively)
35
+ * a selection among the account's projects.
36
+ */
37
+ export declare function resolveDevelopmentProject(session: OnboardingSession, settings: Settings, options: DevelopmentProjectOptions, cwd?: string): Promise<DevelopmentProject | undefined>;
38
+ /**
39
+ * Creates the chosen project if needed, mints a development key limited to
40
+ * runtime translation, and saves both to .env.local. Callers inspect
41
+ * .env.local first; the key is never printed.
42
+ */
43
+ export declare function provisionDevelopmentCredentials(session: OnboardingSession, project: DevelopmentProject, settings: Settings, framework: SupportedFrameworks | undefined, cwd?: string): Promise<void>;