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":"setupViteSPA.js","names":[],"sources":["../../src/setup/setupViteSPA.ts"],"sourcesContent":["import { createDiagnosticMessage } from 'generaltranslation/diagnostics';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from '../console/logger.js';\n\ntype SetupViteSPAOptions = {\n appDirectory: string;\n configFilepath: string;\n defaultLocale: string;\n locales: string[];\n translationsDir?: string;\n};\n\nconst defaultBootstrapFilename = 'gt-entry.ts';\nconst alternateBootstrapFilename = 'gt-bootstrap.ts';\n\nfunction getBootstrapConflictError(filename: string): string {\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The Vite bootstrap file already exists',\n why: `GT will not overwrite an existing src/${filename} file`,\n fix: 'Move or rename that file and rerun `npx gt@latest`',\n });\n}\n\nfunction getLoaderContent(translationsImport: string): string {\n return `export default async function loadTranslations(locale: string) {\n const translations = await import(\\`${translationsImport}/\\${locale}.json\\`);\n return translations.default;\n}\n`;\n}\n\nfunction isGeneratedLoader(content: string): boolean {\n return /^export default async function loadTranslations\\(locale: string\\) \\{\\r?\\n const translations = await import\\(`[^`]+\\/\\$\\{locale\\}\\.json`\\);\\r?\\n return translations\\.default;\\r?\\n\\}\\r?\\n?$/.test(\n content\n );\n}\n\nfunction toRelativeImport(fromDirectory: string, toPath: string): string {\n const relativePath = path\n .relative(fromDirectory, toPath)\n .split(path.sep)\n .join(path.posix.sep);\n return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n}\n\nfunction getEntryImport(\n appDirectory: string,\n sourceDirectory: string,\n source: string\n): string {\n const sourcePath = source.replace(/[?#].*$/, '');\n const entryPath = sourcePath.startsWith('/')\n ? path.resolve(appDirectory, `.${sourcePath}`)\n : path.resolve(appDirectory, sourcePath);\n return toRelativeImport(sourceDirectory, entryPath).replace(\n /\\.(?:[cm]?[jt]sx?)$/i,\n ''\n );\n}\n\nfunction getBootstrapEntry(bootstrap: string): string | undefined {\n return bootstrap.match(/await\\s+import\\(\\s*(['\"])([^'\"]+)\\1\\s*\\)/)?.[2];\n}\n\nfunction getModuleEntry(indexHtml: string): {\n script: string;\n source: string;\n} {\n const moduleScripts = indexHtml.match(\n /<script\\b[^>]*\\btype=(['\"])module\\1[^>]*>\\s*<\\/script>/gi\n );\n for (const script of moduleScripts ?? []) {\n const source = script.match(/\\bsrc=(['\"])([^'\"]+)\\1/i)?.[2];\n if (source) return { script, source };\n }\n\n throw new Error(\n createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'No Vite module entry was found in index.html',\n fix: 'Add a module script for the app entry and rerun `npx gt@latest`',\n })\n );\n}\n\nexport async function setupViteSPA({\n appDirectory,\n configFilepath,\n defaultLocale,\n locales,\n translationsDir,\n}: SetupViteSPAOptions): Promise<void> {\n const indexHtmlPath = path.join(appDirectory, 'index.html');\n const sourceDirectory = path.join(appDirectory, 'src');\n const indexHtml = await fs.promises.readFile(indexHtmlPath, 'utf8');\n const { script, source } = getModuleEntry(indexHtml);\n const declaredEntryImport = getEntryImport(\n appDirectory,\n sourceDirectory,\n source\n );\n const configuredBootstrap = source.match(\n /^\\/?src\\/(gt-entry\\.ts|gt-bootstrap\\.ts)(?:[?#].*)?$/\n )?.[1];\n const isAlreadyConfigured = configuredBootstrap !== undefined;\n const bootstrapFilename =\n configuredBootstrap ??\n (declaredEntryImport === './gt-entry'\n ? alternateBootstrapFilename\n : defaultBootstrapFilename);\n const bootstrapPath = path.join(sourceDirectory, bootstrapFilename);\n let existingBootstrap: string | undefined;\n\n if (fs.existsSync(bootstrapPath)) {\n existingBootstrap = await fs.promises.readFile(bootstrapPath, 'utf8');\n if (!existingBootstrap.includes('initializeGTSPA')) {\n throw new Error(getBootstrapConflictError(bootstrapFilename));\n }\n }\n\n const entryImport = isAlreadyConfigured\n ? existingBootstrap && getBootstrapEntry(existingBootstrap)\n : declaredEntryImport;\n if (!entryImport) {\n throw new Error(\n createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The existing Vite bootstrap has no app entry import',\n fix: 'Restore the app entry import and rerun `npx gt@latest`',\n })\n );\n }\n\n await fs.promises.mkdir(sourceDirectory, { recursive: true });\n\n let loadTranslationsImport = '';\n let loadTranslationsOption = 'gtConfig';\n if (translationsDir) {\n const translationsPath = path.resolve(appDirectory, translationsDir);\n const loaderPath = path.join(sourceDirectory, 'loadTranslations.ts');\n const translationsImport = toRelativeImport(\n sourceDirectory,\n translationsPath\n );\n const existingLoader = fs.existsSync(loaderPath)\n ? await fs.promises.readFile(loaderPath, 'utf8')\n : undefined;\n if (!existingLoader || isGeneratedLoader(existingLoader)) {\n await fs.promises.writeFile(\n loaderPath,\n getLoaderContent(translationsImport)\n );\n }\n\n await fs.promises.mkdir(translationsPath, { recursive: true });\n for (const locale of new Set(locales)) {\n if (locale === defaultLocale) continue;\n const stubPath = path.join(translationsPath, `${locale}.json`);\n if (!fs.existsSync(stubPath)) {\n await fs.promises.writeFile(stubPath, '{}\\n');\n }\n }\n\n loadTranslationsImport =\n \"import loadTranslations from './loadTranslations';\\n\";\n loadTranslationsOption = '{ ...gtConfig, loadTranslations }';\n }\n\n const configImport = toRelativeImport(\n sourceDirectory,\n path.resolve(appDirectory, configFilepath)\n );\n await fs.promises.writeFile(\n bootstrapPath,\n `import { initializeGTSPA } from 'gt-react';\nimport gtConfig from '${configImport}';\n${loadTranslationsImport}\nawait initializeGTSPA(${loadTranslationsOption});\n\nawait import('${entryImport}');\n`\n );\n\n if (!isAlreadyConfigured) {\n const updatedScript = script.replace(source, `/src/${bootstrapFilename}`);\n await fs.promises.writeFile(\n indexHtmlPath,\n indexHtml.replace(script, updatedScript)\n );\n }\n\n logger.success('Configured initializeGTSPA for this Vite application.');\n}\n"],"mappings":";;;;;AAaA,MAAM,2BAA2B;AACjC,MAAM,6BAA6B;AAEnC,SAAS,0BAA0B,UAA0B;AAC3D,QAAO,wBAAwB;EAC7B,QAAQ;EACR,UAAU;EACV,cAAc;EACd,KAAK,yCAAyC,SAAS;EACvD,KAAK;EACN,CAAC;;AAGJ,SAAS,iBAAiB,oBAAoC;AAC5D,QAAO;wCAC+B,mBAAmB;;;;;AAM3D,SAAS,kBAAkB,SAA0B;AACnD,QAAO,iMAAiM,KACtM,QACD;;AAGH,SAAS,iBAAiB,eAAuB,QAAwB;CACvE,MAAM,eAAe,KAClB,SAAS,eAAe,OAAO,CAC/B,MAAM,KAAK,IAAI,CACf,KAAK,KAAK,MAAM,IAAI;AACvB,QAAO,aAAa,WAAW,IAAI,GAAG,eAAe,KAAK;;AAG5D,SAAS,eACP,cACA,iBACA,QACQ;CACR,MAAM,aAAa,OAAO,QAAQ,WAAW,GAAG;AAIhD,QAAO,iBAAiB,iBAHN,WAAW,WAAW,IAAI,GACxC,KAAK,QAAQ,cAAc,IAAI,aAAa,GAC5C,KAAK,QAAQ,cAAc,WAAW,CACS,CAAC,QAClD,wBACA,GACD;;AAGH,SAAS,kBAAkB,WAAuC;AAChE,QAAO,UAAU,MAAM,2CAA2C,GAAG;;AAGvE,SAAS,eAAe,WAGtB;CACA,MAAM,gBAAgB,UAAU,MAC9B,2DACD;AACD,MAAK,MAAM,UAAU,iBAAiB,EAAE,EAAE;EACxC,MAAM,SAAS,OAAO,MAAM,0BAA0B,GAAG;AACzD,MAAI,OAAQ,QAAO;GAAE;GAAQ;GAAQ;;AAGvC,OAAM,IAAI,MACR,wBAAwB;EACtB,QAAQ;EACR,UAAU;EACV,cAAc;EACd,KAAK;EACN,CAAC,CACH;;AAGH,eAAsB,aAAa,EACjC,cACA,gBACA,eACA,SACA,mBACqC;CACrC,MAAM,gBAAgB,KAAK,KAAK,cAAc,aAAa;CAC3D,MAAM,kBAAkB,KAAK,KAAK,cAAc,MAAM;CACtD,MAAM,YAAY,MAAM,GAAG,SAAS,SAAS,eAAe,OAAO;CACnE,MAAM,EAAE,QAAQ,WAAW,eAAe,UAAU;CACpD,MAAM,sBAAsB,eAC1B,cACA,iBACA,OACD;CACD,MAAM,sBAAsB,OAAO,MACjC,uDACD,GAAG;CACJ,MAAM,sBAAsB,wBAAwB,KAAA;CACpD,MAAM,oBACJ,wBACC,wBAAwB,eACrB,6BACA;CACN,MAAM,gBAAgB,KAAK,KAAK,iBAAiB,kBAAkB;CACnE,IAAI;AAEJ,KAAI,GAAG,WAAW,cAAc,EAAE;AAChC,sBAAoB,MAAM,GAAG,SAAS,SAAS,eAAe,OAAO;AACrE,MAAI,CAAC,kBAAkB,SAAS,kBAAkB,CAChD,OAAM,IAAI,MAAM,0BAA0B,kBAAkB,CAAC;;CAIjE,MAAM,cAAc,sBAChB,qBAAqB,kBAAkB,kBAAkB,GACzD;AACJ,KAAI,CAAC,YACH,OAAM,IAAI,MACR,wBAAwB;EACtB,QAAQ;EACR,UAAU;EACV,cAAc;EACd,KAAK;EACN,CAAC,CACH;AAGH,OAAM,GAAG,SAAS,MAAM,iBAAiB,EAAE,WAAW,MAAM,CAAC;CAE7D,IAAI,yBAAyB;CAC7B,IAAI,yBAAyB;AAC7B,KAAI,iBAAiB;EACnB,MAAM,mBAAmB,KAAK,QAAQ,cAAc,gBAAgB;EACpE,MAAM,aAAa,KAAK,KAAK,iBAAiB,sBAAsB;EACpE,MAAM,qBAAqB,iBACzB,iBACA,iBACD;EACD,MAAM,iBAAiB,GAAG,WAAW,WAAW,GAC5C,MAAM,GAAG,SAAS,SAAS,YAAY,OAAO,GAC9C,KAAA;AACJ,MAAI,CAAC,kBAAkB,kBAAkB,eAAe,CACtD,OAAM,GAAG,SAAS,UAChB,YACA,iBAAiB,mBAAmB,CACrC;AAGH,QAAM,GAAG,SAAS,MAAM,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAC9D,OAAK,MAAM,UAAU,IAAI,IAAI,QAAQ,EAAE;AACrC,OAAI,WAAW,cAAe;GAC9B,MAAM,WAAW,KAAK,KAAK,kBAAkB,GAAG,OAAO,OAAO;AAC9D,OAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,OAAM,GAAG,SAAS,UAAU,UAAU,OAAO;;AAIjD,2BACE;AACF,2BAAyB;;CAG3B,MAAM,eAAe,iBACnB,iBACA,KAAK,QAAQ,cAAc,eAAe,CAC3C;AACD,OAAM,GAAG,SAAS,UAChB,eACA;wBACoB,aAAa;EACnC,uBAAuB;wBACD,uBAAuB;;gBAE/B,YAAY;EAEzB;AAED,KAAI,CAAC,qBAAqB;EACxB,MAAM,gBAAgB,OAAO,QAAQ,QAAQ,QAAQ,oBAAoB;AACzE,QAAM,GAAG,SAAS,UAChB,eACA,UAAU,QAAQ,QAAQ,cAAc,CACzC;;AAGH,QAAO,QAAQ,wDAAwD"}
1
+ {"version":3,"file":"setupViteSPA.js","names":[],"sources":["../../src/setup/setupViteSPA.ts"],"sourcesContent":["import { parse } from '@babel/parser';\nimport { createDiagnosticMessage } from 'generaltranslation/diagnostics';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from '../console/logger.js';\nimport { Libraries } from '../types/libraries.js';\n\ntype SetupViteSPAOptions = {\n appDirectory: string;\n configFilepath: string;\n defaultLocale: string;\n locales: string[];\n translationsDir?: string;\n previousTranslationsDir?: string;\n};\n\nconst defaultBootstrapFilename = 'gt-entry.ts';\nconst alternateBootstrapFilename = 'gt-bootstrap.ts';\n\nfunction getBootstrapConflictError(filename: string): string {\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The Vite bootstrap file already exists',\n why: `GT will not overwrite an existing src/${filename} file`,\n fix: 'Move or rename that file and rerun `npx gt@latest`',\n });\n}\n\nfunction getLoaderContent(translationsImport: string): string {\n return `export default async function loadTranslations(locale: string) {\n const translations = await import(\\`${translationsImport}/\\${locale}.json\\`);\n return translations.default;\n}\n`;\n}\n\n/**\n * Top-level statements, or undefined for syntax this inspector cannot parse\n * but Vite may accept, such as decorators.\n */\nfunction parseModule(content: string, filename: string) {\n try {\n return parse(content, {\n sourceType: 'module',\n // JSX would reject `<T>x` assertions, which .ts files may use.\n plugins: /\\.[cm]?ts$/i.test(filename)\n ? ['typescript']\n : ['typescript', 'jsx'],\n }).program.body;\n } catch {\n return undefined;\n }\n}\n\nfunction toRelativeImport(fromDirectory: string, toPath: string): string {\n const relativePath = path\n .relative(fromDirectory, toPath)\n .split(path.sep)\n .join(path.posix.sep);\n return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n}\n\nfunction getEntryPath(appDirectory: string, source: string): string {\n const sourcePath = source.replace(/[?#].*$/, '');\n return sourcePath.startsWith('/')\n ? path.resolve(appDirectory, `.${sourcePath}`)\n : path.resolve(appDirectory, sourcePath);\n}\n\nfunction getBootstrapEntry(bootstrap: string): string | undefined {\n return bootstrap.match(/await\\s+import\\(\\s*(['\"])([^'\"]+)\\1\\s*\\)/)?.[2];\n}\n\nfunction getModuleEntry(indexHtml: string): {\n script: string;\n source: string;\n} {\n const moduleScripts = indexHtml.match(\n /<script\\b[^>]*\\btype=(['\"])module\\1[^>]*>\\s*<\\/script>/gi\n );\n for (const script of moduleScripts ?? []) {\n const source = script.match(/\\bsrc=(['\"])([^'\"]+)\\1/i)?.[2];\n if (source) return { script, source };\n }\n\n throw new Error(\n createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'No Vite module entry was found in index.html',\n fix: 'Add a module script for the app entry and rerun `npx gt@latest`',\n })\n );\n}\n\n/**\n * Reads the Vite entry and bootstrap without writing, so setup can report an\n * unsupported layout before changing any file.\n */\nexport async function inspectViteSPA(appDirectory: string) {\n const indexHtmlPath = path.join(appDirectory, 'index.html');\n const sourceDirectory = path.join(appDirectory, 'src');\n const indexHtml = await fs.promises.readFile(indexHtmlPath, 'utf8');\n const { script, source } = getModuleEntry(indexHtml);\n const declaredEntryPath = getEntryPath(appDirectory, source);\n const declaredEntryImport = toRelativeImport(\n sourceDirectory,\n declaredEntryPath\n ).replace(/\\.(?:[cm]?[jt]sx?)$/i, '');\n const configuredBootstrap = source.match(\n /^\\/?src\\/(gt-entry\\.ts|gt-bootstrap\\.ts)(?:[?#].*)?$/\n )?.[1];\n let customBootstrap: string | undefined;\n if (!configuredBootstrap && fs.existsSync(declaredEntryPath)) {\n const entry = await fs.promises.readFile(declaredEntryPath, 'utf8');\n const mentionsInitializer = entry.includes('initializeGTSPA');\n // Unparseable entries fall back to the text check: a false positive only\n // asks for manual review, while a miss would initialize GT twice.\n const importsInitializer =\n parseModule(entry, declaredEntryPath)?.some(\n (statement) =>\n statement.type === 'ImportDeclaration' &&\n statement.source.value === Libraries.GT_REACT &&\n statement.importKind !== 'type' &&\n statement.specifiers.some(\n (specifier) =>\n (specifier.type === 'ImportNamespaceSpecifier' &&\n mentionsInitializer) ||\n (specifier.type === 'ImportSpecifier' &&\n specifier.importKind !== 'type' &&\n specifier.imported.type === 'Identifier' &&\n specifier.imported.name === 'initializeGTSPA')\n )\n ) ?? mentionsInitializer;\n if (importsInitializer) {\n customBootstrap = path.relative(appDirectory, declaredEntryPath);\n }\n }\n const isAlreadyConfigured = configuredBootstrap !== undefined;\n const bootstrapFilename =\n configuredBootstrap ??\n (declaredEntryImport === './gt-entry'\n ? alternateBootstrapFilename\n : defaultBootstrapFilename);\n const bootstrapPath = path.join(sourceDirectory, bootstrapFilename);\n let existingBootstrap: string | undefined;\n\n if (!customBootstrap && fs.existsSync(bootstrapPath)) {\n existingBootstrap = await fs.promises.readFile(bootstrapPath, 'utf8');\n if (!existingBootstrap.includes('initializeGTSPA')) {\n throw new Error(getBootstrapConflictError(bootstrapFilename));\n }\n }\n\n const entryImport = isAlreadyConfigured\n ? existingBootstrap && getBootstrapEntry(existingBootstrap)\n : declaredEntryImport;\n if (!entryImport) {\n throw new Error(\n createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The existing Vite bootstrap has no app entry import',\n fix: 'Restore the app entry import and rerun `npx gt@latest`',\n })\n );\n }\n return {\n indexHtmlPath,\n sourceDirectory,\n indexHtml,\n script,\n source,\n isAlreadyConfigured,\n customBootstrap,\n bootstrapFilename,\n bootstrapPath,\n entryImport,\n };\n}\n\nexport type ViteLoaderResult = 'written' | 'custom' | 'missing';\n\n/**\n * Points the generated src/loadTranslations.ts at translationsDir and adds\n * empty locale stubs. Only a template matching the previous config is\n * refreshed; other existing loaders are left unchanged. An absent loader\n * is only created with `create`.\n */\nexport async function writeViteLoader({\n appDirectory,\n defaultLocale,\n locales,\n translationsDir,\n previousTranslationsDir,\n create,\n}: Omit<SetupViteSPAOptions, 'configFilepath' | 'translationsDir'> & {\n translationsDir: string;\n create: boolean;\n}): Promise<ViteLoaderResult> {\n const sourceDirectory = path.join(appDirectory, 'src');\n const translationsPath = path.resolve(appDirectory, translationsDir);\n const loaderPath = path.join(sourceDirectory, 'loadTranslations.ts');\n const existingLoader = fs.existsSync(loaderPath)\n ? await fs.promises.readFile(loaderPath, 'utf8')\n : undefined;\n if (existingLoader === undefined && !create) return 'missing';\n const content = getLoaderContent(\n toRelativeImport(sourceDirectory, translationsPath)\n );\n const previousContent =\n previousTranslationsDir === undefined\n ? undefined\n : getLoaderContent(\n toRelativeImport(\n sourceDirectory,\n path.resolve(appDirectory, previousTranslationsDir)\n )\n );\n const normalizedLoader = existingLoader?.replace(/\\r\\n/g, '\\n').trimEnd();\n const custom =\n existingLoader !== undefined &&\n normalizedLoader !== content.trimEnd() &&\n normalizedLoader !== previousContent?.trimEnd();\n\n // Stubs first, so a directory failure leaves no loader pointing at it.\n await fs.promises.mkdir(translationsPath, { recursive: true });\n for (const locale of new Set(locales)) {\n if (locale === defaultLocale) continue;\n const stubPath = path.join(translationsPath, `${locale}.json`);\n if (!fs.existsSync(stubPath)) {\n await fs.promises.writeFile(stubPath, '{}\\n');\n }\n }\n if (custom) return 'custom';\n await fs.promises.writeFile(loaderPath, content);\n return 'written';\n}\n\nfunction getLoaderExport(\n content: string\n): 'default' | 'loadTranslations' | undefined {\n const statements = parseModule(content, 'loadTranslations.ts');\n if (!statements) return undefined;\n const names = new Set<string>();\n for (const statement of statements) {\n // @babel/types omits the interface form the parser emits, which is erased\n // at compile time and leaves no runtime default export.\n if (\n statement.type === 'ExportDefaultDeclaration' &&\n (statement.declaration.type as string) !== 'TSInterfaceDeclaration'\n )\n names.add('default');\n if (\n statement.type !== 'ExportNamedDeclaration' ||\n statement.exportKind === 'type'\n )\n continue;\n for (const specifier of statement.specifiers) {\n if (\n specifier.type === 'ExportSpecifier' &&\n specifier.exportKind !== 'type'\n ) {\n names.add(\n specifier.exported.type === 'Identifier'\n ? specifier.exported.name\n : specifier.exported.value\n );\n }\n }\n const declaration = statement.declaration;\n if (\n declaration?.type === 'FunctionDeclaration' &&\n !declaration.declare &&\n declaration.id\n ) {\n names.add(declaration.id.name);\n }\n if (declaration?.type === 'VariableDeclaration' && !declaration.declare) {\n for (const variable of declaration.declarations) {\n if (variable.id.type === 'Identifier') names.add(variable.id.name);\n }\n }\n }\n if (names.has('default')) return 'default';\n if (names.has('loadTranslations')) return 'loadTranslations';\n return undefined;\n}\n\nexport async function setupViteSPA({\n appDirectory,\n configFilepath,\n defaultLocale,\n locales,\n translationsDir,\n previousTranslationsDir,\n}: SetupViteSPAOptions): Promise<{\n loader?: ViteLoaderResult;\n manualAction?: string;\n}> {\n const {\n indexHtmlPath,\n sourceDirectory,\n indexHtml,\n script,\n source,\n isAlreadyConfigured,\n customBootstrap,\n bootstrapFilename,\n bootstrapPath,\n entryImport,\n } = await inspectViteSPA(appDirectory);\n\n // An app-owned initializer may have custom imports and options. Nesting a\n // generated initializer around it would initialize GT twice.\n if (customBootstrap) {\n return {\n manualAction: `Verify the existing GT bootstrap ${customBootstrap} uses ${configFilepath}${translationsDir ? ` and loads translations from ${translationsDir}` : ' with CDN loading'}`,\n };\n }\n\n await fs.promises.mkdir(sourceDirectory, { recursive: true });\n\n let loadTranslationsImport = '';\n let loadTranslationsOption = 'gtConfig';\n let loader: ViteLoaderResult | undefined;\n if (translationsDir) {\n loader = await writeViteLoader({\n appDirectory,\n defaultLocale,\n locales,\n translationsDir,\n previousTranslationsDir,\n create: true,\n });\n const loaderExport =\n loader === 'custom'\n ? getLoaderExport(\n await fs.promises.readFile(\n path.join(sourceDirectory, 'loadTranslations.ts'),\n 'utf8'\n )\n )\n : 'default';\n if (!loaderExport) {\n return {\n loader,\n manualAction: `Update your custom src/loadTranslations.ts to load translations from ${translationsDir} and export a default or named loadTranslations function, then rerun gt init`,\n };\n }\n loadTranslationsImport =\n loaderExport === 'default'\n ? \"import loadTranslations from './loadTranslations';\\n\"\n : \"import { loadTranslations } from './loadTranslations';\\n\";\n loadTranslationsOption = '{ ...gtConfig, loadTranslations }';\n }\n\n const configImport = toRelativeImport(\n sourceDirectory,\n path.resolve(appDirectory, configFilepath)\n );\n await fs.promises.writeFile(\n bootstrapPath,\n `import { initializeGTSPA } from '${Libraries.GT_REACT}';\nimport gtConfig from '${configImport}';\n${loadTranslationsImport}\nawait initializeGTSPA(${loadTranslationsOption});\n\nawait import('${entryImport}');\n`\n );\n\n if (!isAlreadyConfigured) {\n const updatedScript = script.replace(source, `/src/${bootstrapFilename}`);\n await fs.promises.writeFile(\n indexHtmlPath,\n indexHtml.replace(script, updatedScript)\n );\n }\n\n logger.success('Configured initializeGTSPA for this Vite application.');\n return {\n loader,\n ...(loader === 'custom' && {\n manualAction: `Verify your preserved custom src/loadTranslations.ts loads translations from ${translationsDir}`,\n }),\n };\n}\n"],"mappings":"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"}
@@ -1,8 +1,17 @@
1
- export declare function getDesiredLocales(existingConfig?: {
1
+ import type { OnboardingSession } from './onboarding.js';
2
+ /**
3
+ * Resolves the default and target locales: explicit flags replace the
4
+ * configured values, which are kept otherwise. Only the default locale has a
5
+ * recommended value.
6
+ */
7
+ export declare function getDesiredLocales(session: OnboardingSession, existingConfig: {
2
8
  defaultLocale?: unknown;
3
9
  locales?: unknown;
4
10
  customMapping?: unknown;
11
+ }, explicit?: {
12
+ defaultLocale?: string;
13
+ locales?: string[];
5
14
  }): Promise<{
6
- defaultLocale: string;
7
- locales: string[];
15
+ defaultLocale?: string;
16
+ locales?: string[];
8
17
  }>;
@@ -1,19 +1,35 @@
1
+ import { validateLocale } from "../console/promptParsing.js";
1
2
  import { promptLocale, promptLocaleList } from "../console/logging.js";
2
3
  import { libraryDefaultLocale } from "generaltranslation/internal";
3
4
  //#region src/setup/userInput.ts
4
- async function getDesiredLocales(existingConfig) {
5
- const configuredDefaultLocale = typeof existingConfig?.defaultLocale === "string" && existingConfig.defaultLocale ? existingConfig.defaultLocale : void 0;
6
- const configuredLocales = Array.isArray(existingConfig?.locales) && existingConfig.locales.every((locale) => typeof locale === "string") ? existingConfig.locales : void 0;
7
- const customMapping = existingConfig?.customMapping && typeof existingConfig.customMapping === "object" ? existingConfig.customMapping : void 0;
5
+ /**
6
+ * Resolves the default and target locales: explicit flags replace the
7
+ * configured values, which are kept otherwise. Only the default locale has a
8
+ * recommended value.
9
+ */
10
+ async function getDesiredLocales(session, existingConfig, explicit = {}) {
11
+ const configuredDefaultLocale = typeof existingConfig.defaultLocale === "string" && existingConfig.defaultLocale ? existingConfig.defaultLocale : void 0;
12
+ const configuredLocales = Array.isArray(existingConfig.locales) && existingConfig.locales.every((locale) => typeof locale === "string") ? existingConfig.locales : void 0;
13
+ const customMapping = existingConfig.customMapping && typeof existingConfig.customMapping === "object" ? existingConfig.customMapping : void 0;
14
+ for (const locale of [...explicit.defaultLocale ? [explicit.defaultLocale] : [], ...explicit.locales ?? []]) if (validateLocale(locale, customMapping) !== true) session.reject(`"${locale}" is not a valid locale`);
8
15
  return {
9
- defaultLocale: configuredDefaultLocale ?? await promptLocale({
10
- message: "What is the default locale for your project?",
11
- defaultValue: libraryDefaultLocale,
12
- customMapping
16
+ defaultLocale: await session.answer("--default-locale", {
17
+ explicit: explicit.defaultLocale,
18
+ configured: configuredDefaultLocale,
19
+ recommended: libraryDefaultLocale,
20
+ ask: () => promptLocale({
21
+ message: "What is the default locale for your project?",
22
+ defaultValue: libraryDefaultLocale,
23
+ customMapping
24
+ })
13
25
  }),
14
- locales: configuredLocales ?? await promptLocaleList({
15
- message: "Which languages would you like to translate your project into?",
16
- customMapping
26
+ locales: await session.answer("--locales", {
27
+ explicit: explicit.locales,
28
+ configured: configuredLocales,
29
+ ask: () => promptLocaleList({
30
+ message: "Which languages would you like to translate your project into?",
31
+ customMapping
32
+ })
17
33
  })
18
34
  };
19
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"userInput.js","names":[],"sources":["../../src/setup/userInput.ts"],"sourcesContent":["import { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { CustomMapping } from 'generaltranslation/types';\nimport { promptLocale, promptLocaleList } from '../console/logging.js';\n\nexport async function getDesiredLocales(existingConfig?: {\n defaultLocale?: unknown;\n locales?: unknown;\n customMapping?: unknown;\n}): Promise<{\n defaultLocale: string;\n locales: string[];\n}> {\n const configuredDefaultLocale =\n typeof existingConfig?.defaultLocale === 'string' &&\n existingConfig.defaultLocale\n ? existingConfig.defaultLocale\n : undefined;\n const configuredLocales =\n Array.isArray(existingConfig?.locales) &&\n existingConfig.locales.every((locale) => typeof locale === 'string')\n ? (existingConfig.locales as string[])\n : undefined;\n // Accept configured aliases (e.g. `french: { code: 'fr' }`) at the prompt.\n const customMapping =\n existingConfig?.customMapping &&\n typeof existingConfig.customMapping === 'object'\n ? (existingConfig.customMapping as CustomMapping)\n : undefined;\n\n // Ask for the default locale\n const defaultLocale =\n configuredDefaultLocale ??\n (await promptLocale({\n message: 'What is the default locale for your project?',\n defaultValue: libraryDefaultLocale,\n customMapping,\n }));\n\n // Ask for the locales\n const locales =\n configuredLocales ??\n (await promptLocaleList({\n message: 'Which languages would you like to translate your project into?',\n customMapping,\n }));\n return { defaultLocale, locales };\n}\n"],"mappings":";;;AAIA,eAAsB,kBAAkB,gBAOrC;CACD,MAAM,0BACJ,OAAO,gBAAgB,kBAAkB,YACzC,eAAe,gBACX,eAAe,gBACf,KAAA;CACN,MAAM,oBACJ,MAAM,QAAQ,gBAAgB,QAAQ,IACtC,eAAe,QAAQ,OAAO,WAAW,OAAO,WAAW,SAAS,GAC/D,eAAe,UAChB,KAAA;CAEN,MAAM,gBACJ,gBAAgB,iBAChB,OAAO,eAAe,kBAAkB,WACnC,eAAe,gBAChB,KAAA;AAkBN,QAAO;EAAE,eAdP,2BACC,MAAM,aAAa;GAClB,SAAS;GACT,cAAc;GACd;GACD,CAAC;EASoB,SALtB,qBACC,MAAM,iBAAiB;GACtB,SAAS;GACT;GACD,CAAC;EAC6B"}
1
+ {"version":3,"file":"userInput.js","names":[],"sources":["../../src/setup/userInput.ts"],"sourcesContent":["import { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { CustomMapping } from 'generaltranslation/types';\nimport { promptLocale, promptLocaleList } from '../console/logging.js';\nimport { validateLocale } from '../console/promptParsing.js';\nimport type { OnboardingSession } from './onboarding.js';\n\n/**\n * Resolves the default and target locales: explicit flags replace the\n * configured values, which are kept otherwise. Only the default locale has a\n * recommended value.\n */\nexport async function getDesiredLocales(\n session: OnboardingSession,\n existingConfig: {\n defaultLocale?: unknown;\n locales?: unknown;\n customMapping?: unknown;\n },\n explicit: { defaultLocale?: string; locales?: string[] } = {}\n): Promise<{\n defaultLocale?: string;\n locales?: string[];\n}> {\n const configuredDefaultLocale =\n typeof existingConfig.defaultLocale === 'string' &&\n existingConfig.defaultLocale\n ? existingConfig.defaultLocale\n : undefined;\n const configuredLocales =\n Array.isArray(existingConfig.locales) &&\n existingConfig.locales.every((locale) => typeof locale === 'string')\n ? (existingConfig.locales as string[])\n : undefined;\n // Accept configured aliases (e.g. `french: { code: 'fr' }`).\n const customMapping =\n existingConfig.customMapping &&\n typeof existingConfig.customMapping === 'object'\n ? (existingConfig.customMapping as CustomMapping)\n : undefined;\n\n for (const locale of [\n ...(explicit.defaultLocale ? [explicit.defaultLocale] : []),\n ...(explicit.locales ?? []),\n ]) {\n if (validateLocale(locale, customMapping) !== true) {\n session.reject(`\"${locale}\" is not a valid locale`);\n }\n }\n\n const defaultLocale = await session.answer('--default-locale', {\n explicit: explicit.defaultLocale,\n configured: configuredDefaultLocale,\n recommended: libraryDefaultLocale,\n ask: () =>\n promptLocale({\n message: 'What is the default locale for your project?',\n defaultValue: libraryDefaultLocale,\n customMapping,\n }),\n });\n\n const locales = await session.answer('--locales', {\n explicit: explicit.locales,\n configured: configuredLocales,\n ask: () =>\n promptLocaleList({\n message:\n 'Which languages would you like to translate your project into?',\n customMapping,\n }),\n });\n return { defaultLocale, locales };\n}\n"],"mappings":";;;;;;;;;AAWA,eAAsB,kBACpB,SACA,gBAKA,WAA2D,EAAE,EAI5D;CACD,MAAM,0BACJ,OAAO,eAAe,kBAAkB,YACxC,eAAe,gBACX,eAAe,gBACf,KAAA;CACN,MAAM,oBACJ,MAAM,QAAQ,eAAe,QAAQ,IACrC,eAAe,QAAQ,OAAO,WAAW,OAAO,WAAW,SAAS,GAC/D,eAAe,UAChB,KAAA;CAEN,MAAM,gBACJ,eAAe,iBACf,OAAO,eAAe,kBAAkB,WACnC,eAAe,gBAChB,KAAA;AAEN,MAAK,MAAM,UAAU,CACnB,GAAI,SAAS,gBAAgB,CAAC,SAAS,cAAc,GAAG,EAAE,EAC1D,GAAI,SAAS,WAAW,EAAE,CAC3B,CACC,KAAI,eAAe,QAAQ,cAAc,KAAK,KAC5C,SAAQ,OAAO,IAAI,OAAO,yBAAyB;AA0BvD,QAAO;EAAE,eAAA,MAtBmB,QAAQ,OAAO,oBAAoB;GAC7D,UAAU,SAAS;GACnB,YAAY;GACZ,aAAa;GACb,WACE,aAAa;IACX,SAAS;IACT,cAAc;IACd;IACD,CAAC;GACL,CAAC;EAYsB,SAAA,MAVF,QAAQ,OAAO,aAAa;GAChD,UAAU,SAAS;GACnB,YAAY;GACZ,WACE,iBAAiB;IACf,SACE;IACF;IACD,CAAC;GACL,CAAC;EAC+B"}
@@ -1,3 +1,19 @@
1
- import { SetupOptions } from '../types/index.js';
2
- import { ReactFrameworkObject } from '../types/index.js';
3
- export declare function handleSetupReactCommand(options: SetupOptions, frameworkObject: ReactFrameworkObject, useDefaults?: boolean): Promise<void>;
1
+ import type { Formatter } from '../hooks/postProcess.js';
2
+ import type { ReactFrameworkObject, SupportedReactFrameworks } from '../types/index.js';
3
+ import type { InitOptions, OnboardingSession } from './onboarding.js';
4
+ /** Everything the React application setup will do, resolved before changes. */
5
+ export type ReactSetupPlan = {
6
+ framework: SupportedReactFrameworks;
7
+ packageJson: Record<string, unknown>;
8
+ /** GT library to install, when it is not installed yet. */
9
+ install?: string;
10
+ nextConfigPath?: string;
11
+ formatter?: Formatter;
12
+ };
13
+ /**
14
+ * Resolves whether and how to set up the React application. Returns
15
+ * undefined when the setup is declined or an answer is still missing.
16
+ */
17
+ export declare function resolveReactSetup(session: OnboardingSession, options: InitOptions, detected: ReactFrameworkObject, configuredFramework?: SupportedReactFrameworks): Promise<ReactSetupPlan | undefined>;
18
+ /** Wraps Next.js App Router content and adds withGTConfig(); installs happen first. */
19
+ export declare function executeReactSetup(session: OnboardingSession, plan: ReactSetupPlan, options: InitOptions): Promise<void>;
@@ -4,134 +4,148 @@ import "../types/libraries.js";
4
4
  import { exitSync, promptConfirm, promptSelect } from "../console/logging.js";
5
5
  import findFilepath from "../fs/findFilepath.js";
6
6
  import { loadConfig } from "../fs/config/loadConfig.js";
7
- import { createOrUpdateConfig } from "../fs/config/setupConfig.js";
8
7
  import { detectFormatter, formatFiles } from "../hooks/postProcess.js";
9
8
  import { handleInitGT } from "../next/parse/handleInitGT.js";
10
9
  import { wrapContentNext } from "../next/parse/wrapContent.js";
11
- import { getPackageManager } from "../utils/packageManager.js";
12
- import { installPackage } from "../utils/installPackage.js";
13
- import { getFrameworkDisplayName } from "./frameworkUtils.js";
10
+ import { getFrameworkDisplayName, getReactFrameworkLibrary } from "./frameworkUtils.js";
14
11
  import chalk from "chalk";
12
+ import { createDiagnosticMessage } from "generaltranslation/internal";
15
13
  //#region src/setup/wizard.ts
16
- async function handleSetupReactCommand(options, frameworkObject, useDefaults = false) {
17
- const frameworkDisplayName = getFrameworkDisplayName(frameworkObject);
18
- if (!useDefaults) {
19
- if (!await promptConfirm({
20
- message: chalk.yellow(`This wizard will configure your ${frameworkDisplayName} project for internationalization with GT. If your project is already using a different i18n library, this wizard may cause issues.
14
+ const cancelledMessage = "Operation cancelled. You can re-run this wizard with: npx gt init";
15
+ /**
16
+ * Resolves whether and how to set up the React application. Returns
17
+ * undefined when the setup is declined or an answer is still missing.
18
+ */
19
+ async function resolveReactSetup(session, options, detected, configuredFramework) {
20
+ const library = getReactFrameworkLibrary(detected);
21
+ if (!await session.answer("--react-setup", {
22
+ explicit: options.reactSetup,
23
+ recommended: true,
24
+ ask: async () => {
25
+ const answer = await promptConfirm({
26
+ message: detected.name === "vite" ? `Would you like to install ${library} and configure initializeGTSPA? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart` : `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,
27
+ defaultValue: true
28
+ });
29
+ if (answer && !await promptConfirm({
30
+ message: chalk.yellow(`This wizard will configure your ${getFrameworkDisplayName(detected)} project for internationalization with GT. If your project is already using a different i18n library, this wizard may cause issues.
21
31
 
22
32
  Make sure you have committed or stashed any changes. Do you want to continue?`),
23
- defaultValue: true,
24
- cancelMessage: "Operation cancelled. You can re-run this wizard with: npx gt setup"
25
- })) {
26
- logger.info("Operation cancelled. You can re-run this wizard with: npx gt setup");
27
- exitSync(0);
28
- }
29
- }
30
- const frameworkType = useDefaults && frameworkObject?.name ? frameworkObject.name : await promptSelect({
31
- message: "Which framework are you using?",
32
- options: [
33
- {
34
- value: "next-app",
35
- label: chalk.blue("Next.js App Router")
36
- },
37
- {
38
- value: "next-pages",
39
- label: chalk.green("Next.js Pages Router")
40
- },
41
- {
42
- value: "vite",
43
- label: chalk.cyan("Vite + React")
44
- },
45
- {
46
- value: "gatsby",
47
- label: chalk.magenta("Gatsby")
48
- },
49
- {
50
- value: "react",
51
- label: chalk.yellow("React")
52
- },
53
- {
54
- value: "redwood",
55
- label: chalk.red("RedwoodJS")
56
- },
57
- {
58
- value: "other",
59
- label: chalk.dim("Other")
33
+ defaultValue: true,
34
+ cancelMessage: cancelledMessage
35
+ })) {
36
+ logger.info(cancelledMessage);
37
+ return exitSync(0);
60
38
  }
61
- ],
62
- defaultValue: frameworkObject?.name || "other"
39
+ return answer;
40
+ }
41
+ })) return void 0;
42
+ const framework = await session.answer("--framework", {
43
+ explicit: options.framework,
44
+ configured: configuredFramework,
45
+ recommended: detected.name,
46
+ ask: () => promptSelect({
47
+ message: "Which framework are you using?",
48
+ options: [
49
+ {
50
+ value: "next-app",
51
+ label: chalk.blue("Next.js App Router")
52
+ },
53
+ {
54
+ value: "next-pages",
55
+ label: chalk.green("Next.js Pages Router")
56
+ },
57
+ {
58
+ value: "vite",
59
+ label: chalk.cyan("Vite + React")
60
+ },
61
+ {
62
+ value: "gatsby",
63
+ label: chalk.magenta("Gatsby")
64
+ },
65
+ {
66
+ value: "react",
67
+ label: chalk.yellow("React")
68
+ },
69
+ {
70
+ value: "redwood",
71
+ label: chalk.red("RedwoodJS")
72
+ },
73
+ {
74
+ value: "other",
75
+ label: chalk.dim("Other")
76
+ }
77
+ ],
78
+ defaultValue: detected.name
79
+ })
63
80
  });
64
- if (frameworkType === "other") {
81
+ if (framework === "other") {
65
82
  logger.error(`Sorry, the wizard doesn't currently support other React frameworks.
66
83
  Please let us know what you would like to see added at https://github.com/generaltranslation/gt/issues`);
67
- exitSync(0);
84
+ return exitSync(0);
68
85
  }
69
- if (frameworkType !== "vite") await createOrUpdateConfig(options.config || "gt.config.json", { framework: frameworkType });
86
+ if (!framework) return void 0;
70
87
  const packageJson = await getPackageJson();
71
88
  if (!packageJson) {
72
- logger.error(chalk.red("No package.json found in the current directory. Run this command from the root of your project."));
73
- exitSync(1);
89
+ session.reject("No package.json found in the current directory. Run this command from the root of your project");
90
+ return;
74
91
  }
75
- if (frameworkType === "next-app" && !isPackageInstalled("gt-next", packageJson)) {
76
- const packageManager = await getPackageManager();
77
- const spinner = logger.createSpinner("timer");
78
- spinner.start(`Installing gt-next with ${packageManager.name}...`);
79
- await installPackage("gt-next", packageManager);
80
- spinner.stop(chalk.green(`Automatically installed gt-next.`));
81
- } else if ([
82
- "next-pages",
83
- "react",
84
- "redwood",
85
- "vite",
86
- "gatsby"
87
- ].includes(frameworkType) && !isPackageInstalled("gt-react", packageJson)) {
88
- const packageManager = await getPackageManager();
89
- const spinner = logger.createSpinner("timer");
90
- spinner.start(`Installing gt-react with ${packageManager.name}...`);
91
- await installPackage("gt-react", packageManager);
92
- spinner.stop(chalk.green(`Automatically installed gt-react.`));
93
- }
94
- const errors = [];
95
- const warnings = [];
96
- let filesUpdated = [];
97
- const tsconfigPath = findFilepath(["tsconfig.json"]);
98
- const tsconfigJson = tsconfigPath ? loadConfig(tsconfigPath) : void 0;
99
- if (frameworkType === "next-app") {
100
- const nextConfigPath = findFilepath([
92
+ const install = framework === "next-app" ? "gt-next" : "gt-react";
93
+ const plan = {
94
+ framework,
95
+ packageJson,
96
+ install: isPackageInstalled(install, packageJson) ? void 0 : install
97
+ };
98
+ if (framework === "next-app") {
99
+ plan.nextConfigPath = findFilepath([
101
100
  "./next.config.js",
102
101
  "./next.config.ts",
103
102
  "./next.config.mjs",
104
103
  "./next.config.mts"
105
104
  ]);
106
- if (!nextConfigPath) {
107
- logger.error("No next.config.[js|ts|mjs|mts] file found.");
108
- exitSync(1);
109
- }
110
- const mergeOptions = {
111
- ...options,
112
- disableIds: true,
113
- disableFormatting: true,
114
- skipTs: true,
115
- addGTProvider: true
116
- };
117
- const spinner = logger.createSpinner();
118
- spinner.start("Wrapping JSX content with <T> tags...");
119
- const { filesUpdated: filesUpdatedNext } = await wrapContentNext(mergeOptions, "gt-next", errors, warnings);
120
- filesUpdated = [...filesUpdated, ...filesUpdatedNext];
121
- spinner.stop(chalk.green(`Success! Updated ${chalk.bold.cyan(filesUpdated.length)} files:\n`) + filesUpdated.map((file) => `${chalk.green("-")} ${file}`).join("\n"));
122
- await handleInitGT(nextConfigPath, errors, warnings, filesUpdated, packageJson, tsconfigJson);
123
- logger.step(chalk.green(`Added withGTConfig() to your ${nextConfigPath} file.`));
105
+ if (!plan.nextConfigPath) session.reject("No next.config.[js|ts|mjs|mts] file found");
106
+ const formatter = await detectFormatter();
107
+ if (formatter && await session.answer("--format", {
108
+ explicit: options.format,
109
+ recommended: true,
110
+ ask: () => promptConfirm({
111
+ message: `Would you like the wizard to auto-format the modified files? ${chalk.dim(`(${formatter})`)}`,
112
+ defaultValue: true
113
+ })
114
+ })) plan.formatter = formatter;
124
115
  }
125
- if (errors.length > 0) logger.error(chalk.red("Failed to write files:\n") + errors.join("\n"));
116
+ return plan;
117
+ }
118
+ /** Wraps Next.js App Router content and adds withGTConfig(); installs happen first. */
119
+ async function executeReactSetup(session, plan, options) {
120
+ if (plan.framework !== "next-app" || !plan.nextConfigPath) return;
121
+ const errors = [];
122
+ const warnings = [];
123
+ const spinner = logger.createSpinner();
124
+ spinner.start("Wrapping JSX content with <T> tags...");
125
+ const { filesUpdated } = await wrapContentNext({
126
+ ...options,
127
+ disableIds: true,
128
+ disableFormatting: true,
129
+ skipTs: true,
130
+ addGTProvider: true
131
+ }, "gt-next", errors, warnings);
132
+ spinner.stop(chalk.green(`Success! Updated ${chalk.bold.cyan(filesUpdated.length)} files:\n`) + filesUpdated.map((file) => `${chalk.green("-")} ${file}`).join("\n"));
133
+ if (filesUpdated.length > 0) session.step("wrapped JSX content");
134
+ const tsconfigPath = findFilepath(["tsconfig.json"]);
135
+ await handleInitGT(plan.nextConfigPath, errors, warnings, filesUpdated, plan.packageJson, tsconfigPath ? loadConfig(tsconfigPath) : void 0);
126
136
  if (warnings.length > 0) logger.warn(chalk.yellow("Warnings encountered:") + "\n" + warnings.map((warning) => `${chalk.yellow("-")} ${warning}`).join("\n"));
127
- const formatter = await detectFormatter();
128
- if (!formatter || filesUpdated.length === 0) return;
129
- if (useDefaults ? true : await promptConfirm({
130
- message: `Would you like the wizard to auto-format the modified files? ${chalk.dim(`(${formatter})`)}`,
131
- defaultValue: true
132
- })) await formatFiles(filesUpdated, formatter);
137
+ if (errors.length > 0) throw new Error(createDiagnosticMessage({
138
+ source: "gt",
139
+ severity: "Error",
140
+ whatHappened: "Setup could not update some application files",
141
+ details: errors,
142
+ fix: "Fix the reported files, then rerun `npx gt init`"
143
+ }));
144
+ logger.step(chalk.green(`Added withGTConfig() to your ${plan.nextConfigPath} file.`));
145
+ session.step(`added withGTConfig() to ${plan.nextConfigPath}`);
146
+ if (plan.formatter) await formatFiles(filesUpdated, plan.formatter);
133
147
  }
134
148
  //#endregion
135
- export { handleSetupReactCommand };
149
+ export { executeReactSetup, resolveReactSetup };
136
150
 
137
151
  //# sourceMappingURL=wizard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.js","names":[],"sources":["../../src/setup/wizard.ts"],"sourcesContent":["import { detectFormatter } from '../hooks/postProcess.js';\nimport { promptSelect } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport chalk from 'chalk';\nimport { promptConfirm } from '../console/logging.js';\nimport { SetupOptions, SupportedReactFrameworks } from '../types/index.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport { formatFiles } from '../hooks/postProcess.js';\nimport { handleInitGT } from '../next/parse/handleInitGT.js';\nimport { getPackageJson, isPackageInstalled } from '../utils/packageJson.js';\nimport { wrapContentNext } from '../next/parse/wrapContent.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport { loadConfig } from '../fs/config/loadConfig.js';\nimport { exitSync } from '../console/logging.js';\nimport { ReactFrameworkObject } from '../types/index.js';\nimport { getFrameworkDisplayName } from './frameworkUtils.js';\nimport { Libraries } from '../types/libraries.js';\n\nexport async function handleSetupReactCommand(\n options: SetupOptions,\n frameworkObject: ReactFrameworkObject,\n useDefaults: boolean = false\n): Promise<void> {\n const frameworkDisplayName = getFrameworkDisplayName(frameworkObject);\n\n // Ask user for confirmation using inquirer\n if (!useDefaults) {\n const answer = await promptConfirm({\n message: chalk.yellow(\n `This wizard will configure your ${frameworkDisplayName} project for internationalization with GT. If your project is already using a different i18n library, this wizard may cause issues.\n\nMake sure you have committed or stashed any changes. Do you want to continue?`\n ),\n defaultValue: true,\n cancelMessage:\n 'Operation cancelled. You can re-run this wizard with: npx gt setup',\n });\n if (!answer) {\n logger.info(\n 'Operation cancelled. You can re-run this wizard with: npx gt setup'\n );\n exitSync(0);\n }\n }\n\n const frameworkType =\n useDefaults && frameworkObject?.name\n ? frameworkObject.name\n : await promptSelect<SupportedReactFrameworks | 'other'>({\n message: 'Which framework are you using?',\n options: [\n { value: 'next-app', label: chalk.blue('Next.js App Router') },\n { value: 'next-pages', label: chalk.green('Next.js Pages Router') },\n { value: 'vite', label: chalk.cyan('Vite + React') },\n { value: 'gatsby', label: chalk.magenta('Gatsby') },\n { value: 'react', label: chalk.yellow('React') },\n { value: 'redwood', label: chalk.red('RedwoodJS') },\n { value: 'other', label: chalk.dim('Other') },\n ],\n defaultValue: frameworkObject?.name || 'other',\n });\n if (frameworkType === 'other') {\n logger.error(\n `Sorry, the wizard doesn't currently support other React frameworks.\nPlease let us know what you would like to see added at https://github.com/generaltranslation/gt/issues`\n );\n exitSync(0);\n }\n\n // Vite setup writes its complete config after locales are collected.\n if (frameworkType !== 'vite') {\n await createOrUpdateConfig(options.config || 'gt.config.json', {\n framework: frameworkType as SupportedReactFrameworks,\n });\n }\n\n const packageJson = await getPackageJson();\n if (!packageJson) {\n logger.error(\n chalk.red(\n 'No package.json found in the current directory. Run this command from the root of your project.'\n )\n );\n exitSync(1);\n }\n // Check if gt-next or gt-react is installed\n if (\n frameworkType === 'next-app' &&\n !isPackageInstalled(Libraries.GT_NEXT, packageJson)\n ) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner('timer');\n spinner.start(\n `Installing ${Libraries.GT_NEXT} with ${packageManager.name}...`\n );\n await installPackage(Libraries.GT_NEXT, packageManager);\n spinner.stop(chalk.green(`Automatically installed ${Libraries.GT_NEXT}.`));\n } else if (\n ['next-pages', 'react', 'redwood', 'vite', 'gatsby'].includes(\n frameworkType\n ) &&\n !isPackageInstalled(Libraries.GT_REACT, packageJson)\n ) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner('timer');\n spinner.start(\n `Installing ${Libraries.GT_REACT} with ${packageManager.name}...`\n );\n await installPackage(Libraries.GT_REACT, packageManager);\n spinner.stop(chalk.green(`Automatically installed ${Libraries.GT_REACT}.`));\n }\n\n const errors: string[] = [];\n const warnings: string[] = [];\n let filesUpdated: string[] = [];\n\n // Read tsconfig.json if it exists\n const tsconfigPath = findFilepath(['tsconfig.json']);\n const tsconfigJson = tsconfigPath ? loadConfig(tsconfigPath) : undefined;\n\n if (frameworkType === 'next-app') {\n // Check if they have a next.config.js file\n const nextConfigPath = findFilepath([\n './next.config.js',\n './next.config.ts',\n './next.config.mjs',\n './next.config.mts',\n ]);\n if (!nextConfigPath) {\n logger.error('No next.config.[js|ts|mjs|mts] file found.');\n exitSync(1);\n }\n\n const mergeOptions = {\n ...options,\n disableIds: true,\n disableFormatting: true,\n skipTs: true,\n addGTProvider: true,\n };\n const spinner = logger.createSpinner();\n spinner.start('Wrapping JSX content with <T> tags...');\n // Wrap all JSX elements in the src directory with a <T> tag, with unique ids\n const { filesUpdated: filesUpdatedNext } = await wrapContentNext(\n mergeOptions,\n Libraries.GT_NEXT,\n errors,\n warnings\n );\n filesUpdated = [...filesUpdated, ...filesUpdatedNext];\n\n spinner.stop(\n chalk.green(\n `Success! Updated ${chalk.bold.cyan(filesUpdated.length)} files:\\n`\n ) + filesUpdated.map((file) => `${chalk.green('-')} ${file}`).join('\\n')\n );\n\n // Add the withGTConfig() function to the next.config.js file\n await handleInitGT(\n nextConfigPath,\n errors,\n warnings,\n filesUpdated,\n packageJson,\n tsconfigJson\n );\n logger.step(\n chalk.green(`Added withGTConfig() to your ${nextConfigPath} file.`)\n );\n }\n\n if (errors.length > 0) {\n logger.error(chalk.red('Failed to write files:\\n') + errors.join('\\n'));\n }\n\n if (warnings.length > 0) {\n logger.warn(\n chalk.yellow('Warnings encountered:') +\n '\\n' +\n warnings.map((warning) => `${chalk.yellow('-')} ${warning}`).join('\\n')\n );\n }\n\n const formatter = await detectFormatter();\n\n if (!formatter || filesUpdated.length === 0) {\n return;\n }\n\n const applyFormatting = useDefaults\n ? true\n : await promptConfirm({\n message: `Would you like the wizard to auto-format the modified files? ${chalk.dim(\n `(${formatter})`\n )}`,\n defaultValue: true,\n });\n // Format updated files if formatters are available\n if (applyFormatting) await formatFiles(filesUpdated, formatter);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAoBA,eAAsB,wBACpB,SACA,iBACA,cAAuB,OACR;CACf,MAAM,uBAAuB,wBAAwB,gBAAgB;AAGrE,KAAI,CAAC;MAWC,CAAC,MAVgB,cAAc;GACjC,SAAS,MAAM,OACb,mCAAmC,qBAAqB;;+EAGzD;GACD,cAAc;GACd,eACE;GACH,CAAC,EACW;AACX,UAAO,KACL,qEACD;AACD,YAAS,EAAE;;;CAIf,MAAM,gBACJ,eAAe,iBAAiB,OAC5B,gBAAgB,OAChB,MAAM,aAAiD;EACrD,SAAS;EACT,SAAS;GACP;IAAE,OAAO;IAAY,OAAO,MAAM,KAAK,qBAAqB;IAAE;GAC9D;IAAE,OAAO;IAAc,OAAO,MAAM,MAAM,uBAAuB;IAAE;GACnE;IAAE,OAAO;IAAQ,OAAO,MAAM,KAAK,eAAe;IAAE;GACpD;IAAE,OAAO;IAAU,OAAO,MAAM,QAAQ,SAAS;IAAE;GACnD;IAAE,OAAO;IAAS,OAAO,MAAM,OAAO,QAAQ;IAAE;GAChD;IAAE,OAAO;IAAW,OAAO,MAAM,IAAI,YAAY;IAAE;GACnD;IAAE,OAAO;IAAS,OAAO,MAAM,IAAI,QAAQ;IAAE;GAC9C;EACD,cAAc,iBAAiB,QAAQ;EACxC,CAAC;AACR,KAAI,kBAAkB,SAAS;AAC7B,SAAO,MACL;wGAED;AACD,WAAS,EAAE;;AAIb,KAAI,kBAAkB,OACpB,OAAM,qBAAqB,QAAQ,UAAU,kBAAkB,EAC7D,WAAW,eACZ,CAAC;CAGJ,MAAM,cAAc,MAAM,gBAAgB;AAC1C,KAAI,CAAC,aAAa;AAChB,SAAO,MACL,MAAM,IACJ,kGACD,CACF;AACD,WAAS,EAAE;;AAGb,KACE,kBAAkB,cAClB,CAAC,mBAAA,WAAsC,YAAY,EACnD;EACA,MAAM,iBAAiB,MAAM,mBAAmB;EAChD,MAAM,UAAU,OAAO,cAAc,QAAQ;AAC7C,UAAQ,MACN,2BAAwC,eAAe,KAAK,KAC7D;AACD,QAAM,eAAA,WAAkC,eAAe;AACvD,UAAQ,KAAK,MAAM,MAAM,mCAAgD,CAAC;YAE1E;EAAC;EAAc;EAAS;EAAW;EAAQ;EAAS,CAAC,SACnD,cACD,IACD,CAAC,mBAAA,YAAuC,YAAY,EACpD;EACA,MAAM,iBAAiB,MAAM,mBAAmB;EAChD,MAAM,UAAU,OAAO,cAAc,QAAQ;AAC7C,UAAQ,MACN,4BAAyC,eAAe,KAAK,KAC9D;AACD,QAAM,eAAA,YAAmC,eAAe;AACxD,UAAQ,KAAK,MAAM,MAAM,oCAAiD,CAAC;;CAG7E,MAAM,SAAmB,EAAE;CAC3B,MAAM,WAAqB,EAAE;CAC7B,IAAI,eAAyB,EAAE;CAG/B,MAAM,eAAe,aAAa,CAAC,gBAAgB,CAAC;CACpD,MAAM,eAAe,eAAe,WAAW,aAAa,GAAG,KAAA;AAE/D,KAAI,kBAAkB,YAAY;EAEhC,MAAM,iBAAiB,aAAa;GAClC;GACA;GACA;GACA;GACD,CAAC;AACF,MAAI,CAAC,gBAAgB;AACnB,UAAO,MAAM,6CAA6C;AAC1D,YAAS,EAAE;;EAGb,MAAM,eAAe;GACnB,GAAG;GACH,YAAY;GACZ,mBAAmB;GACnB,QAAQ;GACR,eAAe;GAChB;EACD,MAAM,UAAU,OAAO,eAAe;AACtC,UAAQ,MAAM,wCAAwC;EAEtD,MAAM,EAAE,cAAc,qBAAqB,MAAM,gBAC/C,cAAA,WAEA,QACA,SACD;AACD,iBAAe,CAAC,GAAG,cAAc,GAAG,iBAAiB;AAErD,UAAQ,KACN,MAAM,MACJ,oBAAoB,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC,WAC1D,GAAG,aAAa,KAAK,SAAS,GAAG,MAAM,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,KAAK,CACzE;AAGD,QAAM,aACJ,gBACA,QACA,UACA,cACA,aACA,aACD;AACD,SAAO,KACL,MAAM,MAAM,gCAAgC,eAAe,QAAQ,CACpE;;AAGH,KAAI,OAAO,SAAS,EAClB,QAAO,MAAM,MAAM,IAAI,2BAA2B,GAAG,OAAO,KAAK,KAAK,CAAC;AAGzE,KAAI,SAAS,SAAS,EACpB,QAAO,KACL,MAAM,OAAO,wBAAwB,GACnC,OACA,SAAS,KAAK,YAAY,GAAG,MAAM,OAAO,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,KAAK,CAC1E;CAGH,MAAM,YAAY,MAAM,iBAAiB;AAEzC,KAAI,CAAC,aAAa,aAAa,WAAW,EACxC;AAYF,KATwB,cACpB,OACA,MAAM,cAAc;EAClB,SAAS,gEAAgE,MAAM,IAC7E,IAAI,UAAU,GACf;EACD,cAAc;EACf,CAAC,CAEe,OAAM,YAAY,cAAc,UAAU"}
1
+ {"version":3,"file":"wizard.js","names":[],"sources":["../../src/setup/wizard.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { detectFormatter, formatFiles } from '../hooks/postProcess.js';\nimport type { Formatter } from '../hooks/postProcess.js';\nimport { exitSync, promptConfirm, promptSelect } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport type {\n ReactFrameworkObject,\n SupportedReactFrameworks,\n} from '../types/index.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport { handleInitGT } from '../next/parse/handleInitGT.js';\nimport { getPackageJson, isPackageInstalled } from '../utils/packageJson.js';\nimport { wrapContentNext } from '../next/parse/wrapContent.js';\nimport { loadConfig } from '../fs/config/loadConfig.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from './frameworkUtils.js';\nimport { Libraries } from '../types/libraries.js';\nimport type { InitOptions, OnboardingSession } from './onboarding.js';\n\n/** Everything the React application setup will do, resolved before changes. */\nexport type ReactSetupPlan = {\n framework: SupportedReactFrameworks;\n packageJson: Record<string, unknown>;\n /** GT library to install, when it is not installed yet. */\n install?: string;\n nextConfigPath?: string;\n formatter?: Formatter;\n};\n\nconst cancelledMessage =\n 'Operation cancelled. You can re-run this wizard with: npx gt init';\n\n/**\n * Resolves whether and how to set up the React application. Returns\n * undefined when the setup is declined or an answer is still missing.\n */\nexport async function resolveReactSetup(\n session: OnboardingSession,\n options: InitOptions,\n detected: ReactFrameworkObject,\n configuredFramework?: SupportedReactFrameworks\n): Promise<ReactSetupPlan | undefined> {\n const library = getReactFrameworkLibrary(detected);\n const setupApp = await session.answer('--react-setup', {\n explicit: options.reactSetup,\n recommended: true,\n ask: async () => {\n const answer = await promptConfirm({\n message:\n detected.name === 'vite'\n ? `Would you like to install ${library} and configure initializeGTSPA? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n : `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n // A prompted opt-in gets a last warning; flags and defaults already chose.\n if (\n answer &&\n !(await promptConfirm({\n message: chalk.yellow(\n `This wizard will configure your ${getFrameworkDisplayName(detected)} project for internationalization with GT. If your project is already using a different i18n library, this wizard may cause issues.\n\nMake sure you have committed or stashed any changes. Do you want to continue?`\n ),\n defaultValue: true,\n cancelMessage: cancelledMessage,\n }))\n ) {\n logger.info(cancelledMessage);\n return exitSync(0);\n }\n return answer;\n },\n });\n if (!setupApp) return undefined;\n\n const framework = await session.answer<SupportedReactFrameworks | 'other'>(\n '--framework',\n {\n explicit: options.framework,\n configured: configuredFramework,\n recommended: detected.name,\n ask: () =>\n promptSelect<SupportedReactFrameworks | 'other'>({\n message: 'Which framework are you using?',\n options: [\n { value: 'next-app', label: chalk.blue('Next.js App Router') },\n { value: 'next-pages', label: chalk.green('Next.js Pages Router') },\n { value: 'vite', label: chalk.cyan('Vite + React') },\n { value: 'gatsby', label: chalk.magenta('Gatsby') },\n { value: 'react', label: chalk.yellow('React') },\n { value: 'redwood', label: chalk.red('RedwoodJS') },\n { value: 'other', label: chalk.dim('Other') },\n ],\n defaultValue: detected.name,\n }),\n }\n );\n if (framework === 'other') {\n logger.error(\n `Sorry, the wizard doesn't currently support other React frameworks.\nPlease let us know what you would like to see added at https://github.com/generaltranslation/gt/issues`\n );\n return exitSync(0);\n }\n if (!framework) return undefined;\n\n const packageJson = await getPackageJson();\n if (!packageJson) {\n session.reject(\n 'No package.json found in the current directory. Run this command from the root of your project'\n );\n return undefined;\n }\n const install =\n framework === 'next-app' ? Libraries.GT_NEXT : Libraries.GT_REACT;\n const plan: ReactSetupPlan = {\n framework,\n packageJson,\n install: isPackageInstalled(install, packageJson) ? undefined : install,\n };\n\n if (framework === 'next-app') {\n plan.nextConfigPath = findFilepath([\n './next.config.js',\n './next.config.ts',\n './next.config.mjs',\n './next.config.mts',\n ]);\n if (!plan.nextConfigPath) {\n session.reject('No next.config.[js|ts|mjs|mts] file found');\n }\n const formatter = await detectFormatter();\n if (\n formatter &&\n (await session.answer('--format', {\n explicit: options.format,\n recommended: true,\n ask: () =>\n promptConfirm({\n message: `Would you like the wizard to auto-format the modified files? ${chalk.dim(\n `(${formatter})`\n )}`,\n defaultValue: true,\n }),\n }))\n ) {\n plan.formatter = formatter;\n }\n }\n return plan;\n}\n\n/** Wraps Next.js App Router content and adds withGTConfig(); installs happen first. */\nexport async function executeReactSetup(\n session: OnboardingSession,\n plan: ReactSetupPlan,\n options: InitOptions\n): Promise<void> {\n if (plan.framework !== 'next-app' || !plan.nextConfigPath) return;\n\n const errors: string[] = [];\n const warnings: string[] = [];\n const spinner = logger.createSpinner();\n spinner.start('Wrapping JSX content with <T> tags...');\n // Wrap all JSX elements in the src directory with a <T> tag, with unique ids\n const { filesUpdated } = await wrapContentNext(\n {\n ...options,\n disableIds: true,\n disableFormatting: true,\n skipTs: true,\n addGTProvider: true,\n },\n Libraries.GT_NEXT,\n errors,\n warnings\n );\n spinner.stop(\n chalk.green(\n `Success! Updated ${chalk.bold.cyan(filesUpdated.length)} files:\\n`\n ) + filesUpdated.map((file) => `${chalk.green('-')} ${file}`).join('\\n')\n );\n if (filesUpdated.length > 0) session.step('wrapped JSX content');\n\n // Add the withGTConfig() function to the next.config.js file\n const tsconfigPath = findFilepath(['tsconfig.json']);\n await handleInitGT(\n plan.nextConfigPath,\n errors,\n warnings,\n filesUpdated,\n plan.packageJson,\n tsconfigPath ? loadConfig(tsconfigPath) : undefined\n );\n\n if (warnings.length > 0) {\n logger.warn(\n chalk.yellow('Warnings encountered:') +\n '\\n' +\n warnings.map((warning) => `${chalk.yellow('-')} ${warning}`).join('\\n')\n );\n }\n if (errors.length > 0) {\n throw new Error(\n createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'Setup could not update some application files',\n details: errors,\n fix: 'Fix the reported files, then rerun `npx gt init`',\n })\n );\n }\n logger.step(\n chalk.green(`Added withGTConfig() to your ${plan.nextConfigPath} file.`)\n );\n session.step(`added withGTConfig() to ${plan.nextConfigPath}`);\n\n if (plan.formatter) await formatFiles(filesUpdated, plan.formatter);\n}\n"],"mappings":"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"}
@@ -103,11 +103,12 @@ export type GenerateSourceOptions = {
103
103
  suppressWarnings: boolean;
104
104
  };
105
105
  export type Framework = typeof Libraries.GT_NEXT | typeof Libraries.GT_REACT | typeof Libraries.GT_REACT_NATIVE | typeof Libraries.GT_TANSTACK_START;
106
+ export declare const SUPPORTED_REACT_FRAMEWORKS: readonly ["next-app", "next-pages", "vite", "gatsby", "react", "redwood"];
106
107
  export type FrameworkObject = {
107
108
  name: 'mintlify';
108
109
  type?: undefined;
109
110
  } | {
110
- name: 'next-app' | 'next-pages' | 'vite' | 'gatsby' | 'redwood' | 'react';
111
+ name: (typeof SUPPORTED_REACT_FRAMEWORKS)[number];
111
112
  type: 'react';
112
113
  };
113
114
  export type ReactFrameworkObject = Extract<FrameworkObject, {
@@ -1 +1,13 @@
1
- export {};
1
+ //#region src/types/index.ts
2
+ const SUPPORTED_REACT_FRAMEWORKS = [
3
+ "next-app",
4
+ "next-pages",
5
+ "vite",
6
+ "gatsby",
7
+ "react",
8
+ "redwood"
9
+ ];
10
+ //#endregion
11
+ export { SUPPORTED_REACT_FRAMEWORKS };
12
+
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":["import type { CustomMapping } from '@generaltranslation/format/types';\nimport type { UserTokenProvider } from 'generaltranslation/api';\nimport type { ModelProvider } from 'generaltranslation/internal';\nimport type { FileFormat } from 'generaltranslation/types';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../formats/files/supportedFiles.js';\nimport {\n ParsingConfigOptions,\n GTParsingFlags,\n BaseParsingFlags,\n ParseFlagsByFileType,\n} from './parsing.js';\nimport { Libraries, InlineLibrary } from './libraries.js';\n\nexport type { Updates } from 'generaltranslation/types';\n\nexport type Options = {\n config: string;\n apiKey?: string;\n projectId?: string;\n versionId?: string;\n jsconfig?: string;\n dictionary?: string;\n src?: string[];\n defaultLocale?: string;\n locales?: string[];\n baseUrl: string;\n inline?: boolean;\n ignoreErrors: boolean;\n suppressWarnings: boolean;\n dryRun: boolean;\n timeout: number;\n force?: boolean;\n stageTranslations?: boolean;\n experimentalLocalizeStaticUrls?: boolean;\n experimentalHideDefaultLocale?: boolean;\n experimentalFlattenJsonFiles?: boolean;\n experimentalLocalizeStaticImports?: boolean;\n experimentalLocalizeRelativeAssets?: boolean;\n experimentalAddHeaderAnchorIds?: 'mintlify' | 'default';\n docsImportRewrites?: Array<{\n match: string;\n replace: string;\n }>;\n};\n\nexport type OpenApiConfig = {\n files: string[];\n translateFields?: string[];\n};\n\nexport type MintlifyOptions = {\n openapi?: OpenApiConfig;\n inferTitleFromFilename?: boolean;\n};\n\nexport type SharedFlags = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n};\n\nexport type TranslateFlags = SharedFlags & {\n versionId?: string;\n jsconfig?: string;\n dictionary?: string;\n defaultLocale?: string;\n locales?: string[];\n ignoreErrors?: boolean;\n src?: string[];\n timeout: number;\n dryRun: boolean;\n saveLocal?: boolean;\n stageTranslations?: boolean;\n setupProject?: boolean; // if true, skip enqueue step\n publish?: boolean;\n force?: boolean;\n forceDownload?: boolean;\n tag?: string;\n message?: string;\n experimentalLocalizeStaticUrls?: boolean;\n experimentalHideDefaultLocale?: boolean;\n experimentalFlattenJsonFiles?: boolean;\n experimentalLocalizeStaticImports?: boolean;\n experimentalLocalizeRelativeAssets?: boolean;\n experimentalAddHeaderAnchorIds?: 'mintlify' | 'default';\n omitConfigIds?: boolean;\n excludeStaticUrls?: string[];\n excludeStaticImports?: string[];\n docsImportRewrites?: Array<{\n match: string;\n replace: string;\n }>;\n};\n\nexport type WrapOptions = {\n src?: string[];\n config: string;\n skipTs: boolean;\n disableIds: boolean;\n disableFormatting: boolean;\n addGTProvider: boolean;\n};\n\nexport type SetupOptions = {\n src?: string[];\n config: string;\n};\n\nexport type GenerateSourceOptions = {\n src?: string[];\n config: string;\n defaultLocale: string;\n dictionary?: string;\n jsconfig?: string;\n inline?: boolean;\n ignoreErrors: boolean;\n suppressWarnings: boolean;\n};\n\nexport type Framework =\n | typeof Libraries.GT_NEXT\n | typeof Libraries.GT_REACT\n | typeof Libraries.GT_REACT_NATIVE\n | typeof Libraries.GT_TANSTACK_START;\n\nexport const SUPPORTED_REACT_FRAMEWORKS = [\n 'next-app',\n 'next-pages',\n 'vite',\n 'gatsby',\n 'react',\n 'redwood',\n] as const;\n\nexport type FrameworkObject =\n | {\n name: 'mintlify';\n type?: undefined;\n }\n | {\n name: (typeof SUPPORTED_REACT_FRAMEWORKS)[number];\n type: 'react';\n };\nexport type ReactFrameworkObject = Extract<FrameworkObject, { type: 'react' }>;\n\nexport type FrameworkType = FrameworkObject['type'];\n\nexport type SupportedFrameworks = FrameworkObject['name'];\nexport type SupportedReactFrameworks = Extract<\n FrameworkObject,\n { type: 'react' }\n>['name'];\n\nexport type SupportedLibraries =\n | InlineLibrary\n | 'next-intl'\n | 'react-i18next'\n | 'next-i18next'\n | 'i18next'\n | 'i18next-icu'\n | 'base';\n\nexport interface ContentScanner {\n scanForContent(\n options: WrapOptions,\n framework: Framework\n ): Promise<{\n errors: string[];\n filesUpdated: string[];\n warnings: string[];\n }>;\n}\n\n// Create a type based on the supported file extensions\nexport type SupportedFileExtension = (typeof SUPPORTED_FILE_EXTENSIONS)[number];\n\n// Update ResolvedFiles to use the dynamic keys\nexport type ResolvedFiles = {\n [K in SupportedFileExtension]?: string[];\n} & {\n gt?: string; // Output glob: /path/[locale].json\n};\n\nexport type TransformOption = {\n match?: string; // regex to match strings, supports capture groups\n replace: string; // string or regex pattern to replace the match with\n // Special placeholders:\n // -> if used in the match string, they will be replaced with the corresponding default locale property value\n // -> if used in the replace string, they will be replaced with the corresponding target locale property value\n // {locale} -> will be replaced with the locale code\n // And any other property from getLocaleProperties()\n};\n\nexport type TransformFiles = {\n [K in SupportedFileExtension]?: TransformOption | string | TransformOption[]; // if a string, only transform the file name\n};\n\nexport type TransformFormats = {\n [K in SupportedFileExtension]?: FileFormat;\n};\n\n// Include patterns can be plain strings or objects with a publish flag\nexport type IncludePattern = string | { pattern: string; publish?: boolean };\n\n// Review requirement for matched files: a boolean applies to all files of the\n// type; the object form opts path groups in/out with globs. exclude wins over\n// include; files matching neither inherit the top-level requiresReview default.\nexport type RequiresReviewConfig =\n | boolean\n | {\n include?: string[];\n exclude?: string[];\n };\n\n// Update FilesOptions to fix the error\nexport type FilesOptions = {\n [K in SupportedFileExtension]?: {\n include: IncludePattern[];\n exclude?: string[];\n transform?: string | TransformOption | TransformOption[];\n transformationFormat?: FileFormat;\n parsingFlags?: BaseParsingFlags; // Flags for parsing inline content\n requiresReview?: RequiresReviewConfig; // Whether translated versions of matched files require approval before use\n };\n} & {\n gt?: {\n output: string; // Output glob: /path/[locale].json\n publish?: boolean; // if true, publish gtjson translations to the CDN\n parsingFlags?: Partial<GTParsingFlags>; // Flags for parsing inline content\n /**\n * @deprecated\n * use `files.gt.parsingFlags.includeSourceCodeContext` instead\n */\n includeSourceCodeContext?: boolean; // Include surrounding source code lines as context for translations (default: false)\n };\n};\n\n// Shared settings between all API-related commands\nexport type FontsConfig = {\n include: string[]; // globs of .ttf/.otf files\n exclude?: string[];\n};\n\nexport type Settings = {\n config: string;\n configDirectory: string;\n baseUrl: string;\n dashboardUrl: string;\n apiKey?: string;\n userTokenProvider?: UserTokenProvider;\n projectId?: string;\n defaultLocale: string;\n locales: string[];\n customMapping?: CustomMapping;\n files: {\n resolvedPaths: ResolvedFiles; // Absolute resolved paths for the default locale\n placeholderPaths: ResolvedFiles; // Absolute placeholder paths for all locales containing [locale]\n transformPaths: TransformFiles; // Absolute transform paths for all locales containing [locale]\n transformFormats: TransformFormats; // Output file format transforms keyed by config file type\n publishPaths: Set<string>; // Absolute paths explicitly opted IN to publishing\n unpublishPaths: Set<string>; // Absolute paths explicitly opted OUT of publishing\n requiresReviewPaths: Set<string>; // Absolute paths whose effective requiresReview policy is true\n parsingFlags: ParseFlagsByFileType;\n gtJson: {\n publish?: boolean; // if true, publish gtjson translations to the CDN\n parsingFlags: GTParsingFlags; // Flags for parsing inline content\n /**\n * @deprecated\n * use {@link files.gt.GTParsingFlags.parsingFlags.includeSourceCodeContext} instead\n */\n includeSourceCodeContext?: boolean; // Include surrounding source code lines as context for translations (default: false)\n };\n };\n stageTranslations: boolean; // if true, always stage the project during translate command\n requiresReview?: boolean; // top-level default: translated artifacts require approval before the client uses them\n publish?: boolean; // if true, publish the translations to the CDN; undefined means no global publish intent\n omitConfigIds?: boolean; // if true, do not write _versionId or _branchId to gt.config.json\n _versionId?: string; // internal use only\n _branchId?: string; // internal use only\n version?: string; // for specifying a custom version id to use. Should be unique\n description?: string;\n src?: string[]; // list of glob patterns for source file scanning\n fonts?: FontsConfig; // fonts to sync to the API before translating\n framework?: SupportedFrameworks;\n options?: AdditionalOptions;\n modelProvider?: ModelProvider;\n tag?: string;\n tagMessage?: string;\n parsingOptions: ParsingConfigOptions;\n branchOptions: BranchOptions;\n // Optional shared static assets config\n sharedStaticAssets?: SharedStaticAssetsConfig;\n};\n\nexport type StaticLocalizationFiles = Pick<\n Settings['files'],\n 'placeholderPaths' | 'resolvedPaths'\n> &\n Partial<Pick<Settings['files'], 'transformPaths' | 'transformFormats'>>;\n\nexport type StaticLocalizationSettings = Pick<\n Settings,\n 'defaultLocale' | 'locales' | 'options'\n> & {\n files?: StaticLocalizationFiles | null;\n};\n\nexport type BranchOptions = {\n currentBranch?: string;\n autoDetectBranches?: boolean;\n remoteName: string; // default 'origin'. The name of the remote to use for auto-detection.\n enabled: boolean; // if true, branching is enabled for the project\n};\n\nexport type AdditionalOptions = {\n // Optional schema to follow while translating JSON files\n jsonSchema?: {\n [fileGlob: string]: JsonSchema;\n };\n // Optional schema to follow while translating YAML files\n yamlSchema?: {\n [fileGlob: string]: YamlSchema;\n };\n // Skip pre-parse validation checks for specific file types\n skipFileValidation?: {\n json?: boolean;\n yaml?: boolean;\n mdx?: boolean;\n };\n // Optional Mintlify-specific options container\n mintlify?: MintlifyOptions;\n docsUrlPattern?: string; // eg /docs/[locale] or /[locale] for localizing static urls in markdown files\n docsImportPattern?: string; // eg /docs/[locale]/foo.md or /[locale]/foo.md for localizing static imports in markdown files\n excludeStaticUrls?: string[]; // A list of file globs to include for static url localization\n excludeStaticImports?: string[]; // A list of file globs to include for static import localization\n docsHideDefaultLocaleImport?: boolean; // if true, hide the default locale in the import path\n copyFiles?: string[]; // array of files to copy to the target locale\n experimentalClearLocaleDirs?: boolean; // if true, clear locale directories before writing translations (default: false)\n clearLocaleDirsExclude?: string[]; // array of glob patterns with [locale] or [locales] placeholder to exclude from clearing (e.g., \"./snippets/[locale]/preserved/**\" or \"./[locales]/static/**\")\n experimentalLocalizeStaticImports?: boolean; // Inserts locale in static import paths in md/mdx files\n // Inserts locale in static url paths in md/mdx files and adds anchor IDs to\n // preserve navigation. The object form enables it with extra behavior.\n experimentalLocalizeStaticUrls?:\n | boolean\n | {\n // Keep links to source pages that have no translation\n skipUntranslatedPages?: boolean;\n };\n experimentalLocalizeRelativeAssets?: boolean; // Rewrites relative asset URLs in translated md/mdx files to valid paths\n experimentalAddHeaderAnchorIds?: 'mintlify' | 'default'; // Format for anchor IDs: 'mintlify' for Mintlify's native {#id} on every heading, 'default' or undefined for escaped inline \\{#id\\}. Can run independently of static url localization\n experimentalHideDefaultLocale?: boolean; // Hides the default locale in the import path\n experimentalFlattenJsonFiles?: boolean; // Flattens JSON files into a single file\n baseDomain?: string; // The base http:// url where the project is hosted\n docsImportRewrites?: Array<{\n match: string; // prefix to match, e.g. '@site/docs'\n replace: string; // replacement prefix, can include [locale] or [defaultLocale]\n }>;\n experimentalCanonicalLocaleKeys?: boolean; // For composite JSON schemas with locale keys, force canonical locale even when alias provided\n saveLocal?: boolean; // if true, detect and save local edits to translated output before enqueuing translations (default: false)\n};\n\nexport type SharedStaticAssetsConfig = {\n include: string | string[];\n outDir?: string;\n publicPath?: string;\n mirrorToLocales?: boolean;\n};\n\nexport type StructuralTransform = {\n sourcePointer: string; // e.g., \"/msg\"\n destinationPointer: string; // e.g., \"/translations/en\"\n};\n\nexport type JsonSchema = {\n preset?: 'mintlify' | 'mintlify-hide-default' | 'openapi';\n structuralTransform?: StructuralTransform[];\n\n // when true, resolve $ref entries in this file before processing\n resolveRefs?: boolean;\n\n // exactly 1 of include or composite must be provided; not both\n\n // specify include if file is not composite\n // multiple target JSONs will be created for each locale,\n // with the only differing content being the specified JSONPath values\n include?: string[]; // array of JSONPaths to include\n\n // specify composite if no new JSONs should be created\n composite?: {\n // The sourceObjectPath is a JSONPath to the array or object containing\n // content in the source and target locales\n // This value is denoted as the \"sourceObject\"\n // Array elements or object sub-elements are denoted as \"sourceItem\"\n [sourceObjectPath: string]: SourceObjectOptions;\n };\n};\n\nexport type YamlSchema = {\n preset?: 'mintlify' | 'openapi';\n include?: string[];\n transform?: TransformOptions;\n};\n\nexport type SourceObjectOptions = {\n type: 'array' | 'object'; // type of the sourceObject;\n // array if the sourceObject is an array\n // -> We will simply add duplicated sourceItems for each locale\n // object if the sourceObject is an object\n // -> We will duplicate the sourceItem for each locale and set the corresponding\n // key with the locale property\n // In both cases, we search the sourceObject for the key that matches the source locale\n\n // Below, relative JSONPaths are relative to the sourceItem root, NOT the sourceObject\n\n include: string[]; // array of relative JSONPaths to include in the translated JSON\n\n // if type is array, there must be a key property in the array element\n // corresponding value should be a locale code\n key?: string; // relative jsonPath to the key to use to distinguish between source and target locales\n // if type is object, the key is simply the JSON key for the sourceItem - this is unnecessary in this case\n\n localeProperty?: string; // specific locale property to use for the key for target locales, default 'code'\n // ex: code, name, nativeName, languageCode, languageName, etc. (values returned by getLocaleProperties)\n\n // optional config for transforming specific fields in the sourceItem\n // for example, helpful for handling urls with locale-specific paths\n transform?: TransformOptions;\n\n // optional list of top-level properties to remove from generated\n // non-default-locale entries (e.g. Mintlify's `default: true` flag on the\n // default language entry, which must not be cloned into other locales)\n omitProperties?: string[];\n\n // optional sorting behavior for array sourceObjects. When set to 'locale',\n // the array will be ordered to match the locales array provided to mergeJson\n // When set to 'localesAlphabetical', the default locale will be placed first\n // and the remaining locales will be ordered alphabetically by locale code\n experimentalSort?: 'locales' | 'localesAlphabetical';\n\n // when true, non-default keyed entries in this composite array are extracted\n // into separate files (using the key value as the directory name) and replaced\n // with $ref pointers. Keeps the source file compact.\n splitEntries?: boolean;\n};\n\nexport type TransformOptions = {\n // relative jsonPath to content to mutate\n [transformPath: string]: TransformOption;\n};\n"],"mappings":";AA6HA,MAAa,6BAA6B;CACxC;CACA;CACA;CACA;CACA;CACA;CACD"}
@@ -9,11 +9,10 @@ export declare function getDevelopmentEnvNames(framework?: SupportedFrameworks):
9
9
  devApiKey: string;
10
10
  };
11
11
  /**
12
- * Whether the project already has a runtime key: the framework's development
13
- * key, or an explicit production key for server runtimes (gt-next, gt-node).
14
- * Browser frameworks only read their prefixed key, so there `settings.apiKey`
15
- * is tooling auth alone. `settings.projectId` already resolves every
16
- * framework prefix. Login is checked separately.
12
+ * Whether the project has the framework's development key, or an explicit
13
+ * API key for a server-only runtime. A tooling key cannot enable client-side
14
+ * hot reload, including in Next.js App Router. `settings.projectId` already
15
+ * resolves every framework prefix. Login is checked separately.
17
16
  */
18
17
  export declare function areCredentialsSet(settings: Pick<Settings, 'projectId' | 'apiKey'>, framework?: SupportedFrameworks): boolean;
19
18
  /**
@@ -38,6 +37,10 @@ type CredentialsEnvFile = {
38
37
  * Git. A referent inside any worktree must already be ignored there; only
39
38
  * .env.local itself gets an ignore rule added, by setCredentials.
40
39
  */
41
- export declare function inspectCredentialsEnvFile(cwd?: string): Promise<CredentialsEnvFile>;
40
+ export declare function inspectCredentialsEnvFile(cwd?: string,
41
+ /** Also checks that the framework's credentials can be saved safely. */
42
+ contentCheck?: {
43
+ framework?: SupportedFrameworks;
44
+ }): Promise<CredentialsEnvFile>;
42
45
  export declare function setCredentials(credentials: Credentials, framework?: SupportedFrameworks, cwd?: string): Promise<void>;
43
46
  export {};