@intlayer/cli 9.5.12 → 9.7.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.
- package/dist/cjs/IntlayerEventListener.cjs.map +1 -1
- package/dist/cjs/_virtual/_utils_asset.cjs +1 -1
- package/dist/cjs/auth/login.cjs +11 -0
- package/dist/cjs/auth/login.cjs.map +1 -1
- package/dist/cjs/auth/setupRepository.cjs +95 -0
- package/dist/cjs/auth/setupRepository.cjs.map +1 -0
- package/dist/cjs/ci.cjs +1 -1
- package/dist/cjs/cli.cjs +59 -14
- package/dist/cjs/cli.cjs.map +1 -1
- package/dist/cjs/editor.cjs +61 -32
- package/dist/cjs/editor.cjs.map +1 -1
- package/dist/cjs/extract.cjs +1 -1
- package/dist/cjs/fill/fill.cjs +25 -9
- package/dist/cjs/fill/fill.cjs.map +1 -1
- package/dist/cjs/fill/translateDictionary.cjs.map +1 -1
- package/dist/cjs/getTargetDictionary.cjs +1 -1
- package/dist/cjs/index.cjs +29 -1
- package/dist/cjs/init.cjs +261 -36
- package/dist/cjs/init.cjs.map +1 -1
- package/dist/cjs/initChromeExtension.cjs +26 -3
- package/dist/cjs/initChromeExtension.cjs.map +1 -1
- package/dist/cjs/initInfra.cjs +6 -0
- package/dist/cjs/initInfra.cjs.map +1 -1
- package/dist/cjs/initMCP.cjs +18 -7
- package/dist/cjs/initMCP.cjs.map +1 -1
- package/dist/cjs/initSkills.cjs +37 -34
- package/dist/cjs/initSkills.cjs.map +1 -1
- package/dist/cjs/listContentDeclaration.cjs +1 -1
- package/dist/cjs/listProjects.cjs +1 -1
- package/dist/cjs/liveSync.cjs.map +1 -1
- package/dist/cjs/pull.cjs +1 -1
- package/dist/cjs/push/push.cjs +1 -1
- package/dist/cjs/reviewDoc/reviewDoc.cjs +1 -1
- package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -1
- package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +1 -1
- package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
- package/dist/cjs/translateDoc/translateDoc.cjs +1 -1
- package/dist/cjs/upgrade.cjs +1 -1
- package/dist/cjs/utils/checkAccess.cjs.map +1 -1
- package/dist/cjs/utils/detectGitRepository.cjs +87 -0
- package/dist/cjs/utils/detectGitRepository.cjs.map +1 -0
- package/dist/cjs/utils/getParentPackageJSON.cjs +1 -1
- package/dist/cjs/utils/isInteractiveTerminal.cjs +12 -0
- package/dist/cjs/utils/isInteractiveTerminal.cjs.map +1 -0
- package/dist/cjs/utils/parseChoice.cjs +21 -0
- package/dist/cjs/utils/parseChoice.cjs.map +1 -0
- package/dist/esm/IntlayerEventListener.mjs.map +1 -1
- package/dist/esm/_virtual/_utils_asset.mjs +1 -1
- package/dist/esm/auth/login.mjs +11 -0
- package/dist/esm/auth/login.mjs.map +1 -1
- package/dist/esm/auth/setupRepository.mjs +90 -0
- package/dist/esm/auth/setupRepository.mjs.map +1 -0
- package/dist/esm/ci.mjs +1 -1
- package/dist/esm/cli.mjs +59 -14
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/editor.mjs +62 -34
- package/dist/esm/editor.mjs.map +1 -1
- package/dist/esm/extract.mjs +1 -1
- package/dist/esm/fill/fill.mjs +25 -9
- package/dist/esm/fill/fill.mjs.map +1 -1
- package/dist/esm/fill/translateDictionary.mjs.map +1 -1
- package/dist/esm/getTargetDictionary.mjs +1 -1
- package/dist/esm/index.mjs +10 -5
- package/dist/esm/init.mjs +253 -38
- package/dist/esm/init.mjs.map +1 -1
- package/dist/esm/initChromeExtension.mjs +24 -4
- package/dist/esm/initChromeExtension.mjs.map +1 -1
- package/dist/esm/initInfra.mjs +6 -0
- package/dist/esm/initInfra.mjs.map +1 -1
- package/dist/esm/initMCP.mjs +21 -11
- package/dist/esm/initMCP.mjs.map +1 -1
- package/dist/esm/initSkills.mjs +37 -36
- package/dist/esm/initSkills.mjs.map +1 -1
- package/dist/esm/listContentDeclaration.mjs +1 -1
- package/dist/esm/listProjects.mjs +1 -1
- package/dist/esm/liveSync.mjs.map +1 -1
- package/dist/esm/pull.mjs +1 -1
- package/dist/esm/push/push.mjs +1 -1
- package/dist/esm/reviewDoc/reviewDoc.mjs +1 -1
- package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -1
- package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +1 -1
- package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
- package/dist/esm/translateDoc/translateDoc.mjs +1 -1
- package/dist/esm/upgrade.mjs +1 -1
- package/dist/esm/utils/checkAccess.mjs.map +1 -1
- package/dist/esm/utils/detectGitRepository.mjs +85 -0
- package/dist/esm/utils/detectGitRepository.mjs.map +1 -0
- package/dist/esm/utils/getParentPackageJSON.mjs +1 -1
- package/dist/esm/utils/isInteractiveTerminal.mjs +11 -0
- package/dist/esm/utils/isInteractiveTerminal.mjs.map +1 -0
- package/dist/esm/utils/parseChoice.mjs +20 -0
- package/dist/esm/utils/parseChoice.mjs.map +1 -0
- package/dist/types/IntlayerEventListener.d.ts +1 -1
- package/dist/types/IntlayerEventListener.d.ts.map +1 -1
- package/dist/types/auth/login.d.ts +5 -0
- package/dist/types/auth/login.d.ts.map +1 -1
- package/dist/types/auth/setupRepository.d.ts +25 -0
- package/dist/types/auth/setupRepository.d.ts.map +1 -0
- package/dist/types/editor.d.ts +10 -0
- package/dist/types/editor.d.ts.map +1 -1
- package/dist/types/fill/fill.d.ts +23 -2
- package/dist/types/fill/fill.d.ts.map +1 -1
- package/dist/types/fill/index.d.ts +2 -2
- package/dist/types/fill/translateDictionary.d.ts +1 -2
- package/dist/types/fill/translateDictionary.d.ts.map +1 -1
- package/dist/types/index.d.ts +11 -6
- package/dist/types/init.d.ts +55 -2
- package/dist/types/init.d.ts.map +1 -1
- package/dist/types/initChromeExtension.d.ts +19 -1
- package/dist/types/initChromeExtension.d.ts.map +1 -1
- package/dist/types/initInfra.d.ts.map +1 -1
- package/dist/types/initMCP.d.ts +16 -2
- package/dist/types/initMCP.d.ts.map +1 -1
- package/dist/types/initSkills.d.ts +23 -6
- package/dist/types/initSkills.d.ts.map +1 -1
- package/dist/types/liveSync.d.ts.map +1 -1
- package/dist/types/reviewDoc/reviewDoc.d.ts +1 -1
- package/dist/types/reviewDoc/reviewDoc.d.ts.map +1 -1
- package/dist/types/reviewDoc/reviewDocBlockAware.d.ts +1 -2
- package/dist/types/reviewDoc/reviewDocBlockAware.d.ts.map +1 -1
- package/dist/types/translateDoc/types.d.ts +1 -1
- package/dist/types/utils/checkAccess.d.ts +2 -1
- package/dist/types/utils/checkAccess.d.ts.map +1 -1
- package/dist/types/utils/detectGitRepository.d.ts +34 -0
- package/dist/types/utils/detectGitRepository.d.ts.map +1 -0
- package/dist/types/utils/isInteractiveTerminal.d.ts +9 -0
- package/dist/types/utils/isInteractiveTerminal.d.ts.map +1 -0
- package/dist/types/utils/parseChoice.d.ts +13 -0
- package/dist/types/utils/parseChoice.d.ts.map +1 -0
- package/dist/types/utils/selectCmsEnvironment.d.ts +1 -1
- package/package.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translateDictionary.cjs","names":["colon","colorize","ANSIColors","colorizeNumber","getAppLogger","getAuthenticatedAPI","retryManager","getUnmergedDictionaries","getPerLocaleDictionary","colorizePath","basename","getFilterMissingTranslationsDictionary","excludeObjectFormat","formatLocale","chunkJSON","reconstructFromSingleChunk","extractTranslatableContent","verifyIdenticObjectFormat","reinsertTranslatedContent","mergeChunks","deepMergeContent","getMultilingualDictionary","insertContentInDictionary"],"sources":["../../../src/fill/translateDictionary.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport type { AIConfig } from '@intlayer/ai';\nimport type { AIOptions } from '@intlayer/api';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { retryManager } from '@intlayer/config/utils';\nimport {\n getFilterMissingTranslationsDictionary,\n getMultilingualDictionary,\n getPerLocaleDictionary,\n insertContentInDictionary,\n} from '@intlayer/core/plugins';\nimport { getUnmergedDictionaries } from '@intlayer/dictionaries-entry/unmerged';\nimport {\n chunkJSON,\n excludeObjectFormat,\n formatLocale,\n type JsonChunk,\n mergeChunks,\n reconstructFromSingleChunk,\n verifyIdenticObjectFormat,\n} from '@intlayer/engine/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getAuthenticatedAPI } from '../utils/checkAccess';\nimport type { AIClient } from '../utils/setupAI';\nimport { deepMergeContent } from './deepMergeContent';\nimport {\n extractTranslatableContent,\n reinsertTranslatedContent,\n} from './extractTranslatableContent';\nimport type { TranslationTask } from './listTranslationsTasks';\n\ntype TranslateDictionaryResult = TranslationTask & {\n dictionaryOutput: Dictionary | null;\n};\n\ntype TranslateDictionaryOptions = {\n mode: 'complete' | 'review';\n aiOptions?: AIOptions;\n fillMetadata?: boolean;\n onHandle?: ReturnType<\n typeof import('@intlayer/engine/utils').getGlobalLimiter\n >;\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n getAbortError?: () => Error | null;\n aiClient?: AIClient;\n aiConfig?: AIConfig;\n};\n\nconst createChunkPreset = (chunkIndex: number, totalChunks: number) => {\n if (totalChunks <= 1) return '';\n return colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n colorizeNumber(chunkIndex + 1),\n colorize(`/${totalChunks}`, ANSIColors.GREY_DARK),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 5 }\n );\n};\n\nconst hasMissingMetadata = (dictionary: Dictionary) =>\n !dictionary.description || !dictionary.title || !dictionary.tags;\n\nconst serializeError = (error: unknown): string => {\n if (error instanceof Error) {\n return error.cause\n ? `${error.message} (cause: ${String(error.cause)})`\n : error.message;\n }\n if (typeof error === 'string') return error;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n};\n\nconst CHUNK_SIZE = 4000;\nconst GROUP_MAX_RETRY = 2;\nconst MAX_RETRY = 3;\nconst RETRY_DELAY = 1000 * 10; // 10 seconds\n\nconst MAX_FOLLOWING_ERRORS = 10; // 10 errors in a row, hard exit the process\nlet followingErrors = 0;\n\nexport const translateDictionary = async (\n task: TranslationTask,\n configuration: IntlayerConfig,\n options?: TranslateDictionaryOptions\n): Promise<TranslateDictionaryResult> => {\n const appLogger = getAppLogger(configuration);\n const intlayerAPI = await getAuthenticatedAPI(configuration);\n\n const { mode, aiOptions, fillMetadata, aiClient, aiConfig } = {\n mode: 'complete',\n fillMetadata: true,\n ...options,\n } as const;\n\n const notifySuccess = () => {\n followingErrors = 0;\n options?.onSuccess?.();\n };\n\n const result = await retryManager(\n async () => {\n const unmergedDictionariesRecord = getUnmergedDictionaries(configuration);\n\n const baseUnmergedDictionary: Dictionary | undefined =\n unmergedDictionariesRecord[task.dictionaryKey]?.find(\n (dict) => dict.localId === task.dictionaryLocalId\n );\n\n if (!baseUnmergedDictionary) {\n appLogger(\n `${task.dictionaryPreset}Dictionary not found in unmergedDictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n return { ...task, dictionaryOutput: null };\n }\n\n let metadata:\n | Pick<Dictionary, 'description' | 'title' | 'tags'>\n | undefined;\n\n if (\n fillMetadata &&\n (hasMissingMetadata(baseUnmergedDictionary) || mode === 'review')\n ) {\n const defaultLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n configuration.internationalization.defaultLocale\n );\n\n appLogger(\n `${task.dictionaryPreset} Filling missing metadata for ${colorizePath(basename(baseUnmergedDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const runAudit = async () => {\n if (aiClient && aiConfig) {\n const result = await aiClient.auditDictionaryMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiConfig,\n });\n\n return {\n data: result,\n };\n }\n\n return await intlayerAPI.ai.auditContentDeclarationMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiOptions,\n });\n };\n\n const metadataResult = options?.onHandle\n ? await options.onHandle(runAudit)\n : await runAudit();\n\n metadata = metadataResult.data?.fileContent;\n }\n\n const translatedContentResults = await Promise.all(\n task.targetLocales.map(async (targetLocale) => {\n /**\n * In complete mode, for large dictionaries, we want to filter all content that is already translated\n *\n * targetLocale: fr\n *\n * { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}\n * { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }\n *\n */\n // Reset to base dictionary for each locale to ensure we filter from the original\n let dictionaryToProcess = structuredClone(baseUnmergedDictionary);\n\n let targetLocaleDictionary: Dictionary;\n\n if (typeof baseUnmergedDictionary.locale === 'string') {\n // For per-locale files, the content is already in simple JSON format (not translation nodes)\n // The base dictionary is already the source locale content\n\n // Look up the target locale dictionary by its locale property.\n // This handles both directory-based paths (/en/file.json → /es/file.json)\n // AND filename-based paths (messages_ICU/en.json → messages_ICU/es.json).\n // Plugins like syncJSON set `dict.locale` correctly, so matching by locale\n // is the only reliable strategy — path string-replacement fails when the\n // locale appears in the filename rather than a directory segment.\n const targetUnmergedDictionary = unmergedDictionariesRecord[\n task.dictionaryKey\n ]?.find(\n (dict) =>\n dict.locale === targetLocale &&\n dict.filePath !== baseUnmergedDictionary.filePath\n );\n\n // Derive the target file path for the fallback (when the file doesn't exist yet).\n // Try directory-style first (/en/ → /es/), then filename-style (en.json → es.json).\n const sourceFilePath = baseUnmergedDictionary.filePath ?? '';\n const derivedTargetFilePath = sourceFilePath.includes(\n `/${task.sourceLocale}/`\n )\n ? sourceFilePath.replace(\n new RegExp(`/${task.sourceLocale}/`, 'g'),\n `/${targetLocale}/`\n )\n : sourceFilePath.replace(\n new RegExp(`(^|/)${task.sourceLocale}(\\\\.[^/]+)$`),\n `$1${targetLocale}$2`\n );\n\n targetLocaleDictionary = targetUnmergedDictionary ?? {\n key: baseUnmergedDictionary.key,\n content: {},\n filePath: derivedTargetFilePath || undefined,\n locale: targetLocale,\n };\n } else {\n // For multilingual dictionaries\n if (mode === 'complete') {\n // Remove all nodes that don't have any content to translate\n dictionaryToProcess = getFilterMissingTranslationsDictionary(\n dictionaryToProcess,\n targetLocale\n );\n }\n\n dictionaryToProcess = getPerLocaleDictionary(\n dictionaryToProcess,\n task.sourceLocale\n );\n\n targetLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n targetLocale\n );\n }\n\n // Filter to only untranslated fields, preserving explicit null values as\n // default-locale fallback markers. Applied after both paths converge so\n // the same logic covers per-locale and multilingual dictionaries.\n if (mode === 'complete') {\n dictionaryToProcess = {\n ...dictionaryToProcess,\n content:\n excludeObjectFormat(\n dictionaryToProcess.content,\n targetLocaleDictionary.content\n ) ?? {},\n };\n }\n\n const localePreset = colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n formatLocale(targetLocale),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 18 }\n );\n\n appLogger(\n `${task.dictionaryPreset}${localePreset} Preparing ${colorizePath(basename(targetLocaleDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const chunkedJsonContent: JsonChunk[] = chunkJSON(\n dictionaryToProcess.content as unknown as Record<string, any>,\n CHUNK_SIZE\n );\n\n const nbOfChunks = chunkedJsonContent.length;\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset} Split into ${colorizeNumber(nbOfChunks)} chunks for translation`,\n {\n level: 'info',\n }\n );\n }\n\n const chunkResult: JsonChunk[] = [];\n\n // Process chunks in parallel (globally throttled) to allow concurrent translation\n const chunkPromises = chunkedJsonContent.map(async (chunk) => {\n const chunkPreset = createChunkPreset(chunk.index, chunk.total);\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} Translating chunk`,\n {\n level: 'info',\n }\n );\n }\n\n const reconstructedChunk = reconstructFromSingleChunk(chunk);\n const {\n extractedContent: chunkExtractedContent,\n translatableDictionary: chunkTranslatableDictionary,\n } = extractTranslatableContent(reconstructedChunk);\n\n const executeTranslation = async () => {\n return await retryManager(\n async () => {\n let translationResult: any;\n\n if (aiClient && aiConfig) {\n translationResult = await aiClient.translateJSON({\n entryFileContent:\n chunkTranslatableDictionary as unknown as JSON,\n presetOutputContent: chunkTranslatableDictionary,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiConfig,\n });\n } else {\n translationResult = await intlayerAPI.ai\n .translateJSON({\n entryFileContent:\n chunkTranslatableDictionary as unknown as JSON,\n presetOutputContent: chunkTranslatableDictionary,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions,\n })\n .then((result) => result.data);\n }\n\n if (!translationResult?.fileContent) {\n throw new Error('No content result');\n }\n\n const { isIdentic, error } = verifyIdenticObjectFormat(\n translationResult.fileContent,\n chunkTranslatableDictionary\n );\n\n if (!isIdentic) {\n throw new Error(\n `Translation result does not match expected format: ${error}`\n );\n }\n\n notifySuccess();\n return reinsertTranslatedContent(\n reconstructedChunk,\n chunkExtractedContent,\n translationResult.fileContent as Record<number, string>\n );\n },\n {\n maxRetry: MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) => {\n const chunkPreset = createChunkPreset(\n chunk.index,\n chunk.total\n );\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} ${colorize('Error filling:', ANSIColors.RED)} ${colorize(serializeError(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n );\n\n followingErrors += 1;\n\n if (followingErrors >= MAX_FOLLOWING_ERRORS) {\n appLogger(`There is something wrong.`, {\n level: 'error',\n });\n process.exit(1); // 1 for error\n }\n },\n }\n )();\n };\n\n const wrapped = options?.onHandle\n ? options.onHandle(executeTranslation) // queued in global limiter\n : executeTranslation(); // no global limiter\n\n return wrapped.then((result) => ({ chunk, result }));\n });\n\n // Wait for all chunks for this locale in parallel (still capped by global limiter)\n const chunkResults = await Promise.all(chunkPromises);\n\n // Maintain order\n chunkResults\n .sort((chunkA, chunkB) => chunkA.chunk.index - chunkB.chunk.index)\n .forEach(({ result }) => {\n chunkResult.push(result);\n });\n\n // Merge translated chunk contents back into a single content object\n const reinsertedContent = mergeChunks(chunkResult);\n\n const merged = {\n ...dictionaryToProcess,\n content: reinsertedContent,\n };\n\n // Merge newly translated content (including explicit null fallbacks) back\n // into the existing target locale content. Applies to both per-locale and\n // multilingual paths so the target always retains previously translated\n // fields and receives null markers where the source has no translation.\n const finalContent = deepMergeContent(\n targetLocaleDictionary.content ?? {},\n merged.content\n );\n\n return [targetLocale, finalContent] as const;\n })\n );\n\n const translatedContent: Partial<Record<Locale, Dictionary['content']>> =\n Object.fromEntries(translatedContentResults);\n\n const baseDictionary = baseUnmergedDictionary.locale\n ? {\n ...baseUnmergedDictionary,\n key: baseUnmergedDictionary.key!,\n content: {},\n }\n : baseUnmergedDictionary;\n\n let dictionaryOutput: Dictionary = {\n ...getMultilingualDictionary(baseDictionary),\n locale: undefined, // Ensure the dictionary is multilingual\n ...metadata,\n };\n\n for (const targetLocale of task.targetLocales) {\n if (translatedContent[targetLocale]) {\n dictionaryOutput = insertContentInDictionary(\n dictionaryOutput,\n translatedContent[targetLocale],\n targetLocale\n );\n }\n }\n\n appLogger(\n `${task.dictionaryPreset} ${colorize('Translation completed successfully', ANSIColors.GREEN)} for ${colorizePath(basename(dictionaryOutput.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n // The dict-level `fill` value may have been lost during JSON serialisation\n // (functions can't be serialised to JSON). Fall back to the config-level\n // fill so that an explicit fill in intlayer.config.ts is honoured.\n const effectiveFillForCheck =\n baseUnmergedDictionary.fill ?? configuration.dictionary?.fill;\n\n if (\n baseUnmergedDictionary.locale &&\n (effectiveFillForCheck === true ||\n effectiveFillForCheck === undefined) &&\n baseUnmergedDictionary.location === 'local'\n ) {\n const dictionaryFilePath = baseUnmergedDictionary\n .filePath!.split('.')\n .slice(0, -1);\n\n const contentIndex = dictionaryFilePath[dictionaryFilePath.length - 1];\n\n return JSON.parse(\n JSON.stringify({\n ...task,\n dictionaryOutput: {\n ...dictionaryOutput,\n fill: undefined,\n filled: true,\n },\n }).replaceAll(\n new RegExp(`\\\\.${contentIndex}\\\\.[a-zA-Z0-9]+`, 'g'),\n `.filled.${contentIndex}.json`\n )\n );\n }\n\n return {\n ...task,\n dictionaryOutput,\n };\n },\n {\n maxRetry: GROUP_MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Error:', ANSIColors.RED)} ${colorize(serializeError(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n ),\n onMaxTryReached: ({ error }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Maximum number of retries reached:', ANSIColors.RED)} ${colorize(serializeError(error), ANSIColors.GREY_DARK)}`,\n {\n level: 'error',\n }\n ),\n }\n )();\n\n return result as TranslateDictionaryResult;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"translateDictionary.cjs","names":["colon","colorize","ANSIColors","colorizeNumber","getAppLogger","getAuthenticatedAPI","retryManager","getUnmergedDictionaries","getPerLocaleDictionary","colorizePath","basename","getFilterMissingTranslationsDictionary","excludeObjectFormat","formatLocale","chunkJSON","reconstructFromSingleChunk","extractTranslatableContent","verifyIdenticObjectFormat","reinsertTranslatedContent","mergeChunks","deepMergeContent","getMultilingualDictionary","insertContentInDictionary"],"sources":["../../../src/fill/translateDictionary.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport type { AIConfig, AIOptions } from '@intlayer/ai';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { retryManager } from '@intlayer/config/utils';\nimport {\n getFilterMissingTranslationsDictionary,\n getMultilingualDictionary,\n getPerLocaleDictionary,\n insertContentInDictionary,\n} from '@intlayer/core/plugins';\nimport { getUnmergedDictionaries } from '@intlayer/dictionaries-entry/unmerged';\nimport {\n chunkJSON,\n excludeObjectFormat,\n formatLocale,\n type JsonChunk,\n mergeChunks,\n reconstructFromSingleChunk,\n verifyIdenticObjectFormat,\n} from '@intlayer/engine/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getAuthenticatedAPI } from '../utils/checkAccess';\nimport type { AIClient } from '../utils/setupAI';\nimport { deepMergeContent } from './deepMergeContent';\nimport {\n extractTranslatableContent,\n reinsertTranslatedContent,\n} from './extractTranslatableContent';\nimport type { TranslationTask } from './listTranslationsTasks';\n\ntype TranslateDictionaryResult = TranslationTask & {\n dictionaryOutput: Dictionary | null;\n};\n\ntype TranslateDictionaryOptions = {\n mode: 'complete' | 'review';\n aiOptions?: AIOptions;\n fillMetadata?: boolean;\n onHandle?: ReturnType<\n typeof import('@intlayer/engine/utils').getGlobalLimiter\n >;\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n getAbortError?: () => Error | null;\n aiClient?: AIClient;\n aiConfig?: AIConfig;\n};\n\nconst createChunkPreset = (chunkIndex: number, totalChunks: number) => {\n if (totalChunks <= 1) return '';\n return colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n colorizeNumber(chunkIndex + 1),\n colorize(`/${totalChunks}`, ANSIColors.GREY_DARK),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 5 }\n );\n};\n\nconst hasMissingMetadata = (dictionary: Dictionary) =>\n !dictionary.description || !dictionary.title || !dictionary.tags;\n\nconst serializeError = (error: unknown): string => {\n if (error instanceof Error) {\n return error.cause\n ? `${error.message} (cause: ${String(error.cause)})`\n : error.message;\n }\n if (typeof error === 'string') return error;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n};\n\nconst CHUNK_SIZE = 4000;\nconst GROUP_MAX_RETRY = 2;\nconst MAX_RETRY = 3;\nconst RETRY_DELAY = 1000 * 10; // 10 seconds\n\nconst MAX_FOLLOWING_ERRORS = 10; // 10 errors in a row, hard exit the process\nlet followingErrors = 0;\n\nexport const translateDictionary = async (\n task: TranslationTask,\n configuration: IntlayerConfig,\n options?: TranslateDictionaryOptions\n): Promise<TranslateDictionaryResult> => {\n const appLogger = getAppLogger(configuration);\n const intlayerAPI = await getAuthenticatedAPI(configuration);\n\n const { mode, aiOptions, fillMetadata, aiClient, aiConfig } = {\n mode: 'complete',\n fillMetadata: true,\n ...options,\n } as const;\n\n const notifySuccess = () => {\n followingErrors = 0;\n options?.onSuccess?.();\n };\n\n const result = await retryManager(\n async () => {\n const unmergedDictionariesRecord = getUnmergedDictionaries(configuration);\n\n const baseUnmergedDictionary: Dictionary | undefined =\n unmergedDictionariesRecord[task.dictionaryKey]?.find(\n (dict) => dict.localId === task.dictionaryLocalId\n );\n\n if (!baseUnmergedDictionary) {\n appLogger(\n `${task.dictionaryPreset}Dictionary not found in unmergedDictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n return { ...task, dictionaryOutput: null };\n }\n\n let metadata:\n | Pick<Dictionary, 'description' | 'title' | 'tags'>\n | undefined;\n\n if (\n fillMetadata &&\n (hasMissingMetadata(baseUnmergedDictionary) || mode === 'review')\n ) {\n const defaultLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n configuration.internationalization.defaultLocale\n );\n\n appLogger(\n `${task.dictionaryPreset} Filling missing metadata for ${colorizePath(basename(baseUnmergedDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const runAudit = async () => {\n if (aiClient && aiConfig) {\n const result = await aiClient.auditDictionaryMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiConfig,\n });\n\n return {\n data: result,\n };\n }\n\n return await intlayerAPI.ai.auditContentDeclarationMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiOptions,\n });\n };\n\n const metadataResult = options?.onHandle\n ? await options.onHandle(runAudit)\n : await runAudit();\n\n metadata = metadataResult.data?.fileContent;\n }\n\n const translatedContentResults = await Promise.all(\n task.targetLocales.map(async (targetLocale) => {\n /**\n * In complete mode, for large dictionaries, we want to filter all content that is already translated\n *\n * targetLocale: fr\n *\n * { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}\n * { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }\n *\n */\n // Reset to base dictionary for each locale to ensure we filter from the original\n let dictionaryToProcess = structuredClone(baseUnmergedDictionary);\n\n let targetLocaleDictionary: Dictionary;\n\n if (typeof baseUnmergedDictionary.locale === 'string') {\n // For per-locale files, the content is already in simple JSON format (not translation nodes)\n // The base dictionary is already the source locale content\n\n // Look up the target locale dictionary by its locale property.\n // This handles both directory-based paths (/en/file.json → /es/file.json)\n // AND filename-based paths (messages_ICU/en.json → messages_ICU/es.json).\n // Plugins like syncJSON set `dict.locale` correctly, so matching by locale\n // is the only reliable strategy — path string-replacement fails when the\n // locale appears in the filename rather than a directory segment.\n const targetUnmergedDictionary = unmergedDictionariesRecord[\n task.dictionaryKey\n ]?.find(\n (dict) =>\n dict.locale === targetLocale &&\n dict.filePath !== baseUnmergedDictionary.filePath\n );\n\n // Derive the target file path for the fallback (when the file doesn't exist yet).\n // Try directory-style first (/en/ → /es/), then filename-style (en.json → es.json).\n const sourceFilePath = baseUnmergedDictionary.filePath ?? '';\n const derivedTargetFilePath = sourceFilePath.includes(\n `/${task.sourceLocale}/`\n )\n ? sourceFilePath.replace(\n new RegExp(`/${task.sourceLocale}/`, 'g'),\n `/${targetLocale}/`\n )\n : sourceFilePath.replace(\n new RegExp(`(^|/)${task.sourceLocale}(\\\\.[^/]+)$`),\n `$1${targetLocale}$2`\n );\n\n targetLocaleDictionary = targetUnmergedDictionary ?? {\n key: baseUnmergedDictionary.key,\n content: {},\n filePath: derivedTargetFilePath || undefined,\n locale: targetLocale,\n };\n } else {\n // For multilingual dictionaries\n if (mode === 'complete') {\n // Remove all nodes that don't have any content to translate\n dictionaryToProcess = getFilterMissingTranslationsDictionary(\n dictionaryToProcess,\n targetLocale\n );\n }\n\n dictionaryToProcess = getPerLocaleDictionary(\n dictionaryToProcess,\n task.sourceLocale\n );\n\n targetLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n targetLocale\n );\n }\n\n // Filter to only untranslated fields, preserving explicit null values as\n // default-locale fallback markers. Applied after both paths converge so\n // the same logic covers per-locale and multilingual dictionaries.\n if (mode === 'complete') {\n dictionaryToProcess = {\n ...dictionaryToProcess,\n content:\n excludeObjectFormat(\n dictionaryToProcess.content,\n targetLocaleDictionary.content\n ) ?? {},\n };\n }\n\n const localePreset = colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n formatLocale(targetLocale),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 18 }\n );\n\n appLogger(\n `${task.dictionaryPreset}${localePreset} Preparing ${colorizePath(basename(targetLocaleDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const chunkedJsonContent: JsonChunk[] = chunkJSON(\n dictionaryToProcess.content as unknown as Record<string, any>,\n CHUNK_SIZE\n );\n\n const nbOfChunks = chunkedJsonContent.length;\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset} Split into ${colorizeNumber(nbOfChunks)} chunks for translation`,\n {\n level: 'info',\n }\n );\n }\n\n const chunkResult: JsonChunk[] = [];\n\n // Process chunks in parallel (globally throttled) to allow concurrent translation\n const chunkPromises = chunkedJsonContent.map(async (chunk) => {\n const chunkPreset = createChunkPreset(chunk.index, chunk.total);\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} Translating chunk`,\n {\n level: 'info',\n }\n );\n }\n\n const reconstructedChunk = reconstructFromSingleChunk(chunk);\n const {\n extractedContent: chunkExtractedContent,\n translatableDictionary: chunkTranslatableDictionary,\n } = extractTranslatableContent(reconstructedChunk);\n\n const executeTranslation = async () => {\n return await retryManager(\n async () => {\n let translationResult: any;\n\n if (aiClient && aiConfig) {\n translationResult = await aiClient.translateJSON({\n entryFileContent:\n chunkTranslatableDictionary as unknown as JSON,\n presetOutputContent: chunkTranslatableDictionary,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiConfig,\n });\n } else {\n translationResult = await intlayerAPI.ai\n .translateJSON({\n entryFileContent: chunkTranslatableDictionary,\n presetOutputContent: chunkTranslatableDictionary,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions,\n })\n .then((result) => result.data);\n }\n\n if (!translationResult?.fileContent) {\n throw new Error('No content result');\n }\n\n const { isIdentic, error } = verifyIdenticObjectFormat(\n translationResult.fileContent,\n chunkTranslatableDictionary\n );\n\n if (!isIdentic) {\n throw new Error(\n `Translation result does not match expected format: ${error}`\n );\n }\n\n notifySuccess();\n return reinsertTranslatedContent(\n reconstructedChunk,\n chunkExtractedContent,\n translationResult.fileContent as Record<number, string>\n );\n },\n {\n maxRetry: MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) => {\n const chunkPreset = createChunkPreset(\n chunk.index,\n chunk.total\n );\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} ${colorize('Error filling:', ANSIColors.RED)} ${colorize(serializeError(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n );\n\n followingErrors += 1;\n\n if (followingErrors >= MAX_FOLLOWING_ERRORS) {\n appLogger(`There is something wrong.`, {\n level: 'error',\n });\n process.exit(1); // 1 for error\n }\n },\n }\n )();\n };\n\n const wrapped = options?.onHandle\n ? options.onHandle(executeTranslation) // queued in global limiter\n : executeTranslation(); // no global limiter\n\n return wrapped.then((result) => ({ chunk, result }));\n });\n\n // Wait for all chunks for this locale in parallel (still capped by global limiter)\n const chunkResults = await Promise.all(chunkPromises);\n\n // Maintain order\n chunkResults\n .sort((chunkA, chunkB) => chunkA.chunk.index - chunkB.chunk.index)\n .forEach(({ result }) => {\n chunkResult.push(result);\n });\n\n // Merge translated chunk contents back into a single content object\n const reinsertedContent = mergeChunks(chunkResult);\n\n const merged = {\n ...dictionaryToProcess,\n content: reinsertedContent,\n };\n\n // Merge newly translated content (including explicit null fallbacks) back\n // into the existing target locale content. Applies to both per-locale and\n // multilingual paths so the target always retains previously translated\n // fields and receives null markers where the source has no translation.\n const finalContent = deepMergeContent(\n targetLocaleDictionary.content ?? {},\n merged.content\n );\n\n return [targetLocale, finalContent] as const;\n })\n );\n\n const translatedContent: Partial<Record<Locale, Dictionary['content']>> =\n Object.fromEntries(translatedContentResults);\n\n const baseDictionary = baseUnmergedDictionary.locale\n ? {\n ...baseUnmergedDictionary,\n key: baseUnmergedDictionary.key!,\n content: {},\n }\n : baseUnmergedDictionary;\n\n let dictionaryOutput: Dictionary = {\n ...getMultilingualDictionary(baseDictionary),\n locale: undefined, // Ensure the dictionary is multilingual\n ...metadata,\n };\n\n for (const targetLocale of task.targetLocales) {\n if (translatedContent[targetLocale]) {\n dictionaryOutput = insertContentInDictionary(\n dictionaryOutput,\n translatedContent[targetLocale],\n targetLocale\n );\n }\n }\n\n appLogger(\n `${task.dictionaryPreset} ${colorize('Translation completed successfully', ANSIColors.GREEN)} for ${colorizePath(basename(dictionaryOutput.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n // The dict-level `fill` value may have been lost during JSON serialisation\n // (functions can't be serialised to JSON). Fall back to the config-level\n // fill so that an explicit fill in intlayer.config.ts is honoured.\n const effectiveFillForCheck =\n baseUnmergedDictionary.fill ?? configuration.dictionary?.fill;\n\n if (\n baseUnmergedDictionary.locale &&\n (effectiveFillForCheck === true ||\n effectiveFillForCheck === undefined) &&\n baseUnmergedDictionary.location === 'local'\n ) {\n const dictionaryFilePath = baseUnmergedDictionary\n .filePath!.split('.')\n .slice(0, -1);\n\n const contentIndex = dictionaryFilePath[dictionaryFilePath.length - 1];\n\n return JSON.parse(\n JSON.stringify({\n ...task,\n dictionaryOutput: {\n ...dictionaryOutput,\n fill: undefined,\n filled: true,\n },\n }).replaceAll(\n new RegExp(`\\\\.${contentIndex}\\\\.[a-zA-Z0-9]+`, 'g'),\n `.filled.${contentIndex}.json`\n )\n );\n }\n\n return {\n ...task,\n dictionaryOutput,\n };\n },\n {\n maxRetry: GROUP_MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Error:', ANSIColors.RED)} ${colorize(serializeError(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n ),\n onMaxTryReached: ({ error }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Maximum number of retries reached:', ANSIColors.RED)} ${colorize(serializeError(error), ANSIColors.GREY_DARK)}`,\n {\n level: 'error',\n }\n ),\n }\n )();\n\n return result as TranslateDictionaryResult;\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
let node_path = require("node:path");
|
|
3
2
|
let _intlayer_engine_cli = require("@intlayer/engine/cli");
|
|
3
|
+
let node_path = require("node:path");
|
|
4
4
|
let _intlayer_config_node = require("@intlayer/config/node");
|
|
5
5
|
let _intlayer_dictionaries_entry_unmerged = require("@intlayer/dictionaries-entry/unmerged");
|
|
6
6
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_auth_sessionToken = require('./auth/sessionToken.cjs');
|
|
3
|
+
const require_auth_login = require('./auth/login.cjs');
|
|
2
4
|
const require_initChromeExtension = require('./initChromeExtension.cjs');
|
|
3
5
|
const require_initInfra = require('./initInfra.cjs');
|
|
4
6
|
const require_initSkills = require('./initSkills.cjs');
|
|
@@ -10,9 +12,12 @@ const require_scan = require('./scan.cjs');
|
|
|
10
12
|
const require_cli = require('./cli.cjs');
|
|
11
13
|
const require_extract = require('./extract.cjs');
|
|
12
14
|
const require_bundle = require('./bundle.cjs');
|
|
15
|
+
const require_utils_checkConfigConsistency = require('./utils/checkConfigConsistency.cjs');
|
|
16
|
+
const require_utils_checkAccess = require('./utils/checkAccess.cjs');
|
|
13
17
|
const require_test_listMissingTranslations = require('./test/listMissingTranslations.cjs');
|
|
14
18
|
const require_test_test = require('./test/test.cjs');
|
|
15
19
|
const require_fill_fill = require('./fill/fill.cjs');
|
|
20
|
+
const require_IntlayerEventListener = require('./IntlayerEventListener.cjs');
|
|
16
21
|
const require_listContentDeclaration = require('./listContentDeclaration.cjs');
|
|
17
22
|
const require_liveSync = require('./liveSync.cjs');
|
|
18
23
|
const require_pull = require('./pull.cjs');
|
|
@@ -24,29 +29,44 @@ const require_translateDoc_translateDoc = require('./translateDoc/translateDoc.c
|
|
|
24
29
|
|
|
25
30
|
exports.BROWSER_EXTENSION_OPTIONS = require_initChromeExtension.BROWSER_EXTENSION_OPTIONS;
|
|
26
31
|
exports.CHROME_EXTENSION_URL = require_initChromeExtension.CHROME_EXTENSION_URL;
|
|
32
|
+
exports.CONTENT_LAYOUT_CHOICES = require_init.CONTENT_LAYOUT_CHOICES;
|
|
33
|
+
exports.DEFAULT_INIT_STEPS = require_init.DEFAULT_INIT_STEPS;
|
|
27
34
|
exports.ESLINT_CONFIG_FILES = require_init.ESLINT_CONFIG_FILES;
|
|
35
|
+
exports.EXTENSION_BROWSERS = require_initChromeExtension.EXTENSION_BROWSERS;
|
|
36
|
+
exports.EXTENSION_URL_BY_BROWSER = require_initChromeExtension.EXTENSION_URL_BY_BROWSER;
|
|
28
37
|
exports.INFRA_MODES = require_initInfra.INFRA_MODES;
|
|
38
|
+
exports.INIT_STEP_COMMANDS = require_init.INIT_STEP_COMMANDS;
|
|
29
39
|
exports.INIT_STEP_GROUPS = require_init.INIT_STEP_GROUPS;
|
|
30
40
|
exports.INSTALL_SCRIPT_URL = require_initInfra.INSTALL_SCRIPT_URL;
|
|
31
41
|
exports.INSTALL_SCRIPT_URL_WINDOWS = require_initInfra.INSTALL_SCRIPT_URL_WINDOWS;
|
|
42
|
+
exports.IntlayerEventListener = require_IntlayerEventListener.IntlayerEventListener;
|
|
32
43
|
exports.LOCALE_ROUTING_CHOICES = require_init.LOCALE_ROUTING_CHOICES;
|
|
33
44
|
exports.MOZILLA_EXTENSION_URL = require_initChromeExtension.MOZILLA_EXTENSION_URL;
|
|
34
45
|
exports.OPT_IN_INIT_STEPS = require_init.OPT_IN_INIT_STEPS;
|
|
35
46
|
exports.PLATFORM_OPTIONS = require_initSkills.PLATFORM_OPTIONS;
|
|
36
47
|
exports.build = require_build.build;
|
|
37
48
|
exports.bundle = require_bundle.bundle;
|
|
49
|
+
exports.checkCMSAuth = require_utils_checkAccess.checkCMSAuth;
|
|
50
|
+
exports.checkConfigConsistency = require_utils_checkConfigConsistency.checkConfigConsistency;
|
|
51
|
+
exports.clearCliSessionToken = require_auth_sessionToken.clearCliSessionToken;
|
|
38
52
|
exports.dirname = require_cli.dirname;
|
|
39
53
|
exports.extract = require_extract.extract;
|
|
40
54
|
exports.fill = require_fill_fill.fill;
|
|
41
55
|
exports.findProjectRoot = require_init.findProjectRoot;
|
|
42
|
-
exports.
|
|
56
|
+
exports.getAuthenticatedAPI = require_utils_checkAccess.getAuthenticatedAPI;
|
|
57
|
+
exports.getContentInitOptions = require_init.getContentInitOptions;
|
|
58
|
+
exports.getInitOptionsForSteps = require_init.getInitOptionsForSteps;
|
|
43
59
|
exports.getInitialInitSteps = require_init.getInitialInitSteps;
|
|
44
60
|
exports.getProjectDependencies = require_init.getProjectDependencies;
|
|
61
|
+
exports.getRemoteEditorRunners = require_editor.getRemoteEditorRunners;
|
|
45
62
|
exports.getRoutingInitOptions = require_init.getRoutingInitOptions;
|
|
46
63
|
exports.init = require_init.init;
|
|
47
64
|
exports.initChromeExtension = require_initChromeExtension.initChromeExtension;
|
|
65
|
+
exports.initCms = require_init.initCms;
|
|
48
66
|
exports.initInfra = require_initInfra.initInfra;
|
|
67
|
+
exports.initRepository = require_init.initRepository;
|
|
49
68
|
exports.initSkills = require_initSkills.initSkills;
|
|
69
|
+
exports.initSteps = require_init.initSteps;
|
|
50
70
|
exports.isEslintInstalled = require_init.isEslintInstalled;
|
|
51
71
|
exports.listContentDeclaration = require_listContentDeclaration.listContentDeclaration;
|
|
52
72
|
exports.listContentDeclarationRows = require_listContentDeclaration.listContentDeclarationRows;
|
|
@@ -54,12 +74,20 @@ exports.listMissingTranslations = require_test_listMissingTranslations.listMissi
|
|
|
54
74
|
exports.listMissingTranslationsWithConfig = require_test_listMissingTranslations.listMissingTranslationsWithConfig;
|
|
55
75
|
exports.listProjectsCommand = require_listProjects.listProjectsCommand;
|
|
56
76
|
exports.liveSync = require_liveSync.liveSync;
|
|
77
|
+
exports.login = require_auth_login.login;
|
|
78
|
+
exports.parseContentLayoutChoice = require_init.parseContentLayoutChoice;
|
|
79
|
+
exports.parseExtensionBrowsers = require_initChromeExtension.parseExtensionBrowsers;
|
|
57
80
|
exports.parseInfraMode = require_initInfra.parseInfraMode;
|
|
58
81
|
exports.parseLocaleRoutingChoice = require_init.parseLocaleRoutingChoice;
|
|
82
|
+
exports.parsePlatform = require_initSkills.parsePlatform;
|
|
83
|
+
exports.parseSkills = require_initSkills.parseSkills;
|
|
59
84
|
exports.promptPlatform = require_initSkills.promptPlatform;
|
|
60
85
|
exports.pull = require_pull.pull;
|
|
61
86
|
exports.push = require_push_push.push;
|
|
62
87
|
exports.pushConfig = require_pushConfig.pushConfig;
|
|
88
|
+
exports.readCliSessionToken = require_auth_sessionToken.readCliSessionToken;
|
|
89
|
+
exports.resolvePlatformWithoutPrompt = require_initSkills.resolvePlatformWithoutPrompt;
|
|
90
|
+
exports.resolveProjectRoot = require_init.resolveProjectRoot;
|
|
63
91
|
exports.reviewDoc = require_reviewDoc_reviewDoc.reviewDoc;
|
|
64
92
|
exports.scan = require_scan.scan;
|
|
65
93
|
exports.searchDoc = require_searchDoc.searchDoc;
|
package/dist/cjs/init.cjs
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_auth_login = require('./auth/login.cjs');
|
|
3
|
+
const require_auth_setupRepository = require('./auth/setupRepository.cjs');
|
|
3
4
|
const require_loadPrompts = require('./loadPrompts.cjs');
|
|
5
|
+
const require_utils_isInteractiveTerminal = require('./utils/isInteractiveTerminal.cjs');
|
|
6
|
+
const require_utils_parseChoice = require('./utils/parseChoice.cjs');
|
|
4
7
|
const require_initChromeExtension = require('./initChromeExtension.cjs');
|
|
5
8
|
const require_initInfra = require('./initInfra.cjs');
|
|
6
9
|
const require_initSkills = require('./initSkills.cjs');
|
|
10
|
+
const require_utils_detectGitRepository = require('./utils/detectGitRepository.cjs');
|
|
7
11
|
const require_initMCP = require('./initMCP.cjs');
|
|
8
|
-
let node_path = require("node:path");
|
|
9
12
|
let _intlayer_engine_cli = require("@intlayer/engine/cli");
|
|
10
13
|
let node_fs = require("node:fs");
|
|
14
|
+
let node_path = require("node:path");
|
|
11
15
|
|
|
12
16
|
//#region src/init.ts
|
|
13
17
|
const findProjectRoot = (startDir) => {
|
|
@@ -18,12 +22,94 @@ const findProjectRoot = (startDir) => {
|
|
|
18
22
|
}
|
|
19
23
|
return startDir;
|
|
20
24
|
};
|
|
25
|
+
/** Resolves the project root from `--project-root`, else the working directory. */
|
|
26
|
+
const resolveProjectRoot = (projectRoot) => findProjectRoot(projectRoot ? (0, node_path.resolve)(projectRoot) : process.cwd());
|
|
21
27
|
/**
|
|
22
28
|
* Steps shown but not pre-selected. The infrastructure installer touches the
|
|
23
29
|
* machine (downloads an app, pulls Docker images) and browser extensions open external URLs
|
|
24
30
|
* rather than modifying the project, so they must be an explicit choice.
|
|
25
31
|
*/
|
|
26
32
|
const OPT_IN_INIT_STEPS = ["infra", "chromeExtension"];
|
|
33
|
+
/**
|
|
34
|
+
* Steps run by `intlayer init` without `--interactive`: install the packages
|
|
35
|
+
* and set up the framework. Every other step has its own command
|
|
36
|
+
* ({@link INIT_STEP_COMMANDS}), so nothing outside the app code is touched
|
|
37
|
+
* unless asked for.
|
|
38
|
+
*/
|
|
39
|
+
const DEFAULT_INIT_STEPS = ["packages", "projectSetup"];
|
|
40
|
+
/**
|
|
41
|
+
* Command running each interactive step on its own, without prompts when every
|
|
42
|
+
* value is passed as a flag. Printed when `--interactive` has no terminal.
|
|
43
|
+
*/
|
|
44
|
+
const INIT_STEP_COMMANDS = {
|
|
45
|
+
packages: "intlayer init packages",
|
|
46
|
+
projectSetup: "intlayer init project [--routing <routing>] [--content <layout>] [--content-format <format>] [--message-format <format>]",
|
|
47
|
+
githubActions: "intlayer init github-actions",
|
|
48
|
+
vscodeExtension: "intlayer init vscode-extension",
|
|
49
|
+
eslint: "intlayer init eslint",
|
|
50
|
+
chromeExtension: "intlayer init extension [--browser <chrome|firefox>]",
|
|
51
|
+
skills: "intlayer init skills [--platform <platform>] [--skills <skills...>]",
|
|
52
|
+
mcp: "intlayer init mcp [--platform <platform>] [--transport <stdio|sse>]",
|
|
53
|
+
lsp: "intlayer init lsp",
|
|
54
|
+
cms: "intlayer init cms",
|
|
55
|
+
repository: "intlayer init repository",
|
|
56
|
+
infra: "intlayer init infra --mode <desktop|docker|compose>"
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Maps setup steps to the {@link initIntlayer} options: every step handled by
|
|
60
|
+
* `initIntlayer` that is not listed is skipped. Explicit `--no-*` flags in
|
|
61
|
+
* `baseOptions` still win over a listed step.
|
|
62
|
+
*/
|
|
63
|
+
const getInitOptionsForSteps = (steps, baseOptions) => ({
|
|
64
|
+
...baseOptions,
|
|
65
|
+
noInstallPackages: baseOptions?.noInstallPackages || !steps.includes("packages"),
|
|
66
|
+
noGitignore: baseOptions?.noGitignore || !steps.includes("projectSetup"),
|
|
67
|
+
noGithubActions: baseOptions?.noGithubActions || !steps.includes("githubActions"),
|
|
68
|
+
noFrameworkSetup: baseOptions?.noFrameworkSetup || !steps.includes("projectSetup"),
|
|
69
|
+
noVscodeExtension: baseOptions?.noVscodeExtension || !steps.includes("vscodeExtension"),
|
|
70
|
+
noLsp: baseOptions?.noLsp || !steps.includes("lsp"),
|
|
71
|
+
noEslint: baseOptions?.noEslint || !steps.includes("eslint"),
|
|
72
|
+
skipFinalMessage: baseOptions?.skipFinalMessage || !steps.includes("projectSetup")
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Runs the given {@link initIntlayer} steps only (packages, project setup, CI,
|
|
76
|
+
* VS Code extension, LSP, lint rules). Backs `intlayer init` and its
|
|
77
|
+
* single-step subcommands.
|
|
78
|
+
*/
|
|
79
|
+
const initSteps = async (projectRoot, steps, options) => {
|
|
80
|
+
await (0, _intlayer_engine_cli.initIntlayer)(resolveProjectRoot(projectRoot), getInitOptionsForSteps(steps, options));
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Logs in to the Intlayer CMS through the browser, then stores the access-key
|
|
84
|
+
* credentials in `.env` and enables the editor in the config file.
|
|
85
|
+
*/
|
|
86
|
+
const initCms = async (projectRoot) => {
|
|
87
|
+
const root = resolveProjectRoot(projectRoot);
|
|
88
|
+
(await require_loadPrompts.loadPrompts()).log.info("Opening your browser to log in to the Intlayer CMS...");
|
|
89
|
+
await require_auth_login.login({
|
|
90
|
+
exitAfter: false,
|
|
91
|
+
onCredentials: (credentials) => (0, _intlayer_engine_cli.setupCmsCredentials)(root, credentials)
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Connects the git repository of the project to its CMS project (and sets
|
|
96
|
+
* its build settings) in the browser, pre-filled with the `origin` remote.
|
|
97
|
+
*/
|
|
98
|
+
const initRepository = async (projectRoot) => {
|
|
99
|
+
const root = resolveProjectRoot(projectRoot);
|
|
100
|
+
const p = await require_loadPrompts.loadPrompts();
|
|
101
|
+
const detectedRepository = require_utils_detectGitRepository.detectGitRepository(root);
|
|
102
|
+
p.log.info(detectedRepository ? `Detected repository: ${detectedRepository.provider} ${detectedRepository.owner}/${detectedRepository.repository}` : "No supported git remote detected: pick the repository in the browser.");
|
|
103
|
+
p.log.info("Opening your browser to connect the repository...");
|
|
104
|
+
await require_auth_setupRepository.setupRepository({ detectedRepository });
|
|
105
|
+
};
|
|
106
|
+
/** Explains why `--interactive` cannot run, and what to run instead. */
|
|
107
|
+
const getNoTerminalMessage = () => [
|
|
108
|
+
"`intlayer init --interactive` needs a terminal to answer its prompts (none is attached, e.g. when run by an AI agent or in CI).",
|
|
109
|
+
"Run the steps directly instead:",
|
|
110
|
+
" intlayer init (installs the packages and sets up the framework)",
|
|
111
|
+
...Object.values(INIT_STEP_COMMANDS).map((command) => ` ${command}`)
|
|
112
|
+
].join("\n");
|
|
27
113
|
/** Grouped checkbox entries of the interactive init flow, in display order. */
|
|
28
114
|
const INIT_STEP_GROUPS = {
|
|
29
115
|
Codebase: [
|
|
@@ -77,15 +163,23 @@ const INIT_STEP_GROUPS = {
|
|
|
77
163
|
hint: "go-to-definition from keys to .content files"
|
|
78
164
|
}
|
|
79
165
|
],
|
|
80
|
-
CMS: [
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
166
|
+
CMS: [
|
|
167
|
+
{
|
|
168
|
+
value: "cms",
|
|
169
|
+
label: "CMS",
|
|
170
|
+
hint: "log in through your browser, then store the credentials in your .env"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
value: "repository",
|
|
174
|
+
label: "Git repository",
|
|
175
|
+
hint: "connect the git repository to the CMS project and set its build settings (GitHub, GitLab, Bitbucket, Codeberg, Gitee)"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
value: "infra",
|
|
179
|
+
label: "Infrastructure (desktop app / self-hosting)",
|
|
180
|
+
hint: "install the desktop app, or self-host with Docker (all-in-one or Compose)"
|
|
181
|
+
}
|
|
182
|
+
]
|
|
89
183
|
};
|
|
90
184
|
/** Locale routing strategies offered by the interactive init flow. */
|
|
91
185
|
const ROUTING_OPTIONS = [
|
|
@@ -118,11 +212,7 @@ const ROUTING_OPTIONS = [
|
|
|
118
212
|
/** Locale routing choices accepted by `--routing`. */
|
|
119
213
|
const LOCALE_ROUTING_CHOICES = ROUTING_OPTIONS.map((option) => option.value);
|
|
120
214
|
/** Validates a `--routing` value, throwing on an unknown choice. */
|
|
121
|
-
const parseLocaleRoutingChoice = (value) =>
|
|
122
|
-
const choice = LOCALE_ROUTING_CHOICES.find((routing) => routing === value);
|
|
123
|
-
if (!choice) throw new Error(`Invalid --routing value "${value}". Expected one of: ${LOCALE_ROUTING_CHOICES.join(", ")}.`);
|
|
124
|
-
return choice;
|
|
125
|
-
};
|
|
215
|
+
const parseLocaleRoutingChoice = (value) => require_utils_parseChoice.parseChoice(value, LOCALE_ROUTING_CHOICES, "--routing");
|
|
126
216
|
/** Maps a routing choice to the init options it sets. */
|
|
127
217
|
const getRoutingInitOptions = (choice) => choice === "none" ? {
|
|
128
218
|
routingMode: "no-prefix",
|
|
@@ -131,6 +221,83 @@ const getRoutingInitOptions = (choice) => choice === "none" ? {
|
|
|
131
221
|
routingMode: choice,
|
|
132
222
|
enableProxy: true
|
|
133
223
|
};
|
|
224
|
+
/** Content declaration layouts offered by the interactive init flow. */
|
|
225
|
+
const CONTENT_LAYOUT_OPTIONS = [
|
|
226
|
+
{
|
|
227
|
+
value: "multilingual",
|
|
228
|
+
label: "Multilingual content declaration",
|
|
229
|
+
hint: "/**/{fileName}.content.{ts,json} — every locale in one file"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
value: "per-locale",
|
|
233
|
+
label: "Per-locale content declaration",
|
|
234
|
+
hint: "/**/{fileName}.{locale}.content.{ts,json}"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
value: "centralized",
|
|
238
|
+
label: "Centralized",
|
|
239
|
+
hint: "/locales/{locale}.{json,po}"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
value: "namespaces",
|
|
243
|
+
label: "Namespaces",
|
|
244
|
+
hint: "/locales/{locale}/{namespace}.{json,po}"
|
|
245
|
+
}
|
|
246
|
+
];
|
|
247
|
+
/** Labels of the content formats offered by the interactive init flow. */
|
|
248
|
+
const CONTENT_FORMAT_LABELS = {
|
|
249
|
+
ts: "TypeScript (.ts)",
|
|
250
|
+
json: "JSON (.json)",
|
|
251
|
+
po: "Gettext (.po)"
|
|
252
|
+
};
|
|
253
|
+
/** Labels of the JSON catalog message formats, in display order. */
|
|
254
|
+
const CATALOG_MESSAGE_FORMAT_OPTIONS = {
|
|
255
|
+
icu: {
|
|
256
|
+
label: "ICU",
|
|
257
|
+
hint: "{count, plural, one {# item} other {# items}}"
|
|
258
|
+
},
|
|
259
|
+
i18next: {
|
|
260
|
+
label: "i18next",
|
|
261
|
+
hint: "{{count}} item, key_one / key_other"
|
|
262
|
+
},
|
|
263
|
+
"vue-i18n": {
|
|
264
|
+
label: "vue-i18n",
|
|
265
|
+
hint: "{count} item | {count} items"
|
|
266
|
+
},
|
|
267
|
+
intlayer: {
|
|
268
|
+
label: "Intlayer",
|
|
269
|
+
hint: "Intlayer dictionary content"
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
/** Content layouts accepted by `--content`. */
|
|
273
|
+
const CONTENT_LAYOUT_CHOICES = CONTENT_LAYOUT_OPTIONS.map((option) => option.value);
|
|
274
|
+
/** Validates a `--content` value, throwing on an unknown layout. */
|
|
275
|
+
const parseContentLayoutChoice = (value) => require_utils_parseChoice.parseChoice(value, CONTENT_LAYOUT_CHOICES, "--content");
|
|
276
|
+
/** Whether a layout + format pair produces a JSON catalog (sync plugin). */
|
|
277
|
+
const isJsonCatalog = (layout, format) => (layout === "centralized" || layout === "namespaces") && format === "json";
|
|
278
|
+
/**
|
|
279
|
+
* Validates `--content` / `--content-format` / `--message-format` and maps
|
|
280
|
+
* them to the init options. The format must be one the layout accepts, and the
|
|
281
|
+
* message format only applies to JSON catalogs.
|
|
282
|
+
*/
|
|
283
|
+
const getContentInitOptions = (layoutValue, formatValue, messageFormatValue) => {
|
|
284
|
+
if (!layoutValue) {
|
|
285
|
+
if (formatValue || messageFormatValue) throw new Error("--content-format and --message-format require --content.");
|
|
286
|
+
return {};
|
|
287
|
+
}
|
|
288
|
+
const contentLayout = parseContentLayoutChoice(layoutValue);
|
|
289
|
+
const contentFormat = formatValue ? require_utils_parseChoice.parseChoice(formatValue, _intlayer_engine_cli.CONTENT_FORMATS_BY_LAYOUT[contentLayout], "--content-format") : void 0;
|
|
290
|
+
if (!messageFormatValue) return {
|
|
291
|
+
contentLayout,
|
|
292
|
+
contentFormat
|
|
293
|
+
};
|
|
294
|
+
if (!isJsonCatalog(contentLayout, contentFormat ?? "json")) throw new Error("--message-format only applies to JSON catalogs (--content centralized | namespaces with json).");
|
|
295
|
+
return {
|
|
296
|
+
contentLayout,
|
|
297
|
+
contentFormat,
|
|
298
|
+
contentMessageFormat: require_utils_parseChoice.parseChoice(messageFormatValue, _intlayer_engine_cli.CATALOG_MESSAGE_FORMATS, "--message-format")
|
|
299
|
+
};
|
|
300
|
+
};
|
|
134
301
|
/** Known ESLint and oxlint configuration file names. */
|
|
135
302
|
const ESLINT_CONFIG_FILES = [
|
|
136
303
|
"eslint.config.js",
|
|
@@ -222,52 +389,110 @@ const runInteractiveInit = async (root, baseOptions) => {
|
|
|
222
389
|
}
|
|
223
390
|
routingOptions = getRoutingInitOptions(selectedRouting);
|
|
224
391
|
}
|
|
392
|
+
let contentOptions = {};
|
|
393
|
+
if (steps.includes("projectSetup") && baseOptions?.contentLayout === void 0 && !hasCompatLib) {
|
|
394
|
+
const contentLayout = await p.select({
|
|
395
|
+
message: "How do you want to declare your content?",
|
|
396
|
+
options: CONTENT_LAYOUT_OPTIONS,
|
|
397
|
+
initialValue: "multilingual"
|
|
398
|
+
});
|
|
399
|
+
if (p.isCancel(contentLayout)) {
|
|
400
|
+
p.cancel("Operation cancelled.");
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const acceptedFormats = _intlayer_engine_cli.CONTENT_FORMATS_BY_LAYOUT[contentLayout];
|
|
404
|
+
const hasTypeScript = (0, node_fs.existsSync)((0, node_path.join)(root, "tsconfig.json"));
|
|
405
|
+
const contentFormat = await p.select({
|
|
406
|
+
message: "Which format for your content?",
|
|
407
|
+
options: acceptedFormats.map((format) => ({
|
|
408
|
+
value: format,
|
|
409
|
+
label: CONTENT_FORMAT_LABELS[format]
|
|
410
|
+
})),
|
|
411
|
+
initialValue: acceptedFormats.includes("ts") && !hasTypeScript ? "json" : acceptedFormats[0]
|
|
412
|
+
});
|
|
413
|
+
if (p.isCancel(contentFormat)) {
|
|
414
|
+
p.cancel("Operation cancelled.");
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
contentOptions = {
|
|
418
|
+
contentLayout,
|
|
419
|
+
contentFormat
|
|
420
|
+
};
|
|
421
|
+
if (isJsonCatalog(contentLayout, contentFormat)) {
|
|
422
|
+
const contentMessageFormat = await p.select({
|
|
423
|
+
message: "Which message format do your JSON catalogs use?",
|
|
424
|
+
options: _intlayer_engine_cli.CATALOG_MESSAGE_FORMATS.map((messageFormat) => ({
|
|
425
|
+
value: messageFormat,
|
|
426
|
+
...CATALOG_MESSAGE_FORMAT_OPTIONS[messageFormat]
|
|
427
|
+
})),
|
|
428
|
+
initialValue: _intlayer_engine_cli.CATALOG_MESSAGE_FORMATS[0]
|
|
429
|
+
});
|
|
430
|
+
if (p.isCancel(contentMessageFormat)) {
|
|
431
|
+
p.cancel("Operation cancelled.");
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
contentOptions = {
|
|
435
|
+
...contentOptions,
|
|
436
|
+
contentMessageFormat
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
}
|
|
225
440
|
const options = {
|
|
226
|
-
...
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
noFrameworkSetup: baseOptions?.noFrameworkSetup || !steps.includes("projectSetup"),
|
|
232
|
-
noVscodeExtension: !steps.includes("vscodeExtension"),
|
|
233
|
-
noLsp: !steps.includes("lsp"),
|
|
234
|
-
noEslint: !steps.includes("eslint"),
|
|
441
|
+
...getInitOptionsForSteps(steps, {
|
|
442
|
+
...baseOptions,
|
|
443
|
+
...routingOptions,
|
|
444
|
+
...contentOptions
|
|
445
|
+
}),
|
|
235
446
|
skipFinalMessage: true
|
|
236
447
|
};
|
|
237
448
|
const { guideUrl } = await (0, _intlayer_engine_cli.initIntlayer)(root, options);
|
|
238
449
|
const skillsPlatform = steps.includes("skills") ? await require_initSkills.initSkills(root) : void 0;
|
|
239
|
-
if (steps.includes("mcp")) await require_initMCP.initMCP(root, skillsPlatform);
|
|
450
|
+
if (steps.includes("mcp")) await require_initMCP.initMCP(root, { platform: skillsPlatform });
|
|
240
451
|
if (steps.includes("infra")) await require_initInfra.initInfra();
|
|
241
452
|
if (steps.includes("chromeExtension")) await require_initChromeExtension.initChromeExtension();
|
|
242
|
-
if (steps.includes("cms"))
|
|
243
|
-
|
|
244
|
-
await require_auth_login.login({
|
|
245
|
-
exitAfter: false,
|
|
246
|
-
onCredentials: (credentials) => (0, _intlayer_engine_cli.setupCmsCredentials)(root, credentials)
|
|
247
|
-
});
|
|
248
|
-
}
|
|
453
|
+
if (steps.includes("cms")) await initCms(root);
|
|
454
|
+
if (steps.includes("repository")) await initRepository(root);
|
|
249
455
|
p.outro("Intlayer initialization complete");
|
|
250
456
|
if (guideUrl) (0, _intlayer_engine_cli.logInitSuccessMessage)(guideUrl);
|
|
251
457
|
};
|
|
458
|
+
/**
|
|
459
|
+
* `intlayer init`: installs the packages and sets up the framework, or, with
|
|
460
|
+
* `interactive`, lets the user pick every setup step. `--interactive` needs a
|
|
461
|
+
* terminal; without one it fails and lists the single-step commands instead.
|
|
462
|
+
*/
|
|
252
463
|
const init = async (projectRoot, options, interactive) => {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
464
|
+
if (!interactive) {
|
|
465
|
+
await initSteps(projectRoot, DEFAULT_INIT_STEPS, options);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (!require_utils_isInteractiveTerminal.isInteractiveTerminal()) {
|
|
469
|
+
(await require_loadPrompts.loadPrompts()).log.error(getNoTerminalMessage());
|
|
470
|
+
process.exitCode = 1;
|
|
256
471
|
return;
|
|
257
472
|
}
|
|
258
|
-
await (
|
|
473
|
+
await runInteractiveInit(resolveProjectRoot(projectRoot), options);
|
|
259
474
|
};
|
|
260
475
|
|
|
261
476
|
//#endregion
|
|
477
|
+
exports.CONTENT_LAYOUT_CHOICES = CONTENT_LAYOUT_CHOICES;
|
|
478
|
+
exports.DEFAULT_INIT_STEPS = DEFAULT_INIT_STEPS;
|
|
262
479
|
exports.ESLINT_CONFIG_FILES = ESLINT_CONFIG_FILES;
|
|
480
|
+
exports.INIT_STEP_COMMANDS = INIT_STEP_COMMANDS;
|
|
263
481
|
exports.INIT_STEP_GROUPS = INIT_STEP_GROUPS;
|
|
264
482
|
exports.LOCALE_ROUTING_CHOICES = LOCALE_ROUTING_CHOICES;
|
|
265
483
|
exports.OPT_IN_INIT_STEPS = OPT_IN_INIT_STEPS;
|
|
266
484
|
exports.findProjectRoot = findProjectRoot;
|
|
485
|
+
exports.getContentInitOptions = getContentInitOptions;
|
|
486
|
+
exports.getInitOptionsForSteps = getInitOptionsForSteps;
|
|
267
487
|
exports.getInitialInitSteps = getInitialInitSteps;
|
|
268
488
|
exports.getProjectDependencies = getProjectDependencies;
|
|
269
489
|
exports.getRoutingInitOptions = getRoutingInitOptions;
|
|
270
490
|
exports.init = init;
|
|
491
|
+
exports.initCms = initCms;
|
|
492
|
+
exports.initRepository = initRepository;
|
|
493
|
+
exports.initSteps = initSteps;
|
|
271
494
|
exports.isEslintInstalled = isEslintInstalled;
|
|
495
|
+
exports.parseContentLayoutChoice = parseContentLayoutChoice;
|
|
272
496
|
exports.parseLocaleRoutingChoice = parseLocaleRoutingChoice;
|
|
497
|
+
exports.resolveProjectRoot = resolveProjectRoot;
|
|
273
498
|
//# sourceMappingURL=init.cjs.map
|