@intlayer/cli 7.5.11 → 7.5.13

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 (70) hide show
  1. package/dist/cjs/cli.cjs +4 -4
  2. package/dist/cjs/cli.cjs.map +1 -1
  3. package/dist/cjs/index.cjs +4 -5
  4. package/dist/cjs/{reviewDoc.cjs → reviewDoc/reviewDoc.cjs} +17 -15
  5. package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -0
  6. package/dist/cjs/{reviewDocBlockAware.cjs → reviewDoc/reviewDocBlockAware.cjs} +12 -8
  7. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -0
  8. package/dist/cjs/translateDoc/index.cjs +8 -0
  9. package/dist/cjs/translateDoc/translateDoc.cjs +74 -0
  10. package/dist/cjs/translateDoc/translateDoc.cjs.map +1 -0
  11. package/dist/cjs/translateDoc/translateFile.cjs +103 -0
  12. package/dist/cjs/translateDoc/translateFile.cjs.map +1 -0
  13. package/dist/cjs/translateDoc/types.cjs +0 -0
  14. package/dist/cjs/translateDoc/validation.cjs +49 -0
  15. package/dist/cjs/translateDoc/validation.cjs.map +1 -0
  16. package/dist/cjs/translation-alignment/planActions.cjs +2 -4
  17. package/dist/cjs/translation-alignment/planActions.cjs.map +1 -1
  18. package/dist/cjs/translation-alignment/segmentDocument.cjs +35 -101
  19. package/dist/cjs/translation-alignment/segmentDocument.cjs.map +1 -1
  20. package/dist/esm/cli.mjs +2 -2
  21. package/dist/esm/cli.mjs.map +1 -1
  22. package/dist/esm/index.mjs +3 -3
  23. package/dist/esm/{reviewDoc.mjs → reviewDoc/reviewDoc.mjs} +14 -12
  24. package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -0
  25. package/dist/esm/{reviewDocBlockAware.mjs → reviewDoc/reviewDocBlockAware.mjs} +11 -7
  26. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -0
  27. package/dist/esm/translateDoc/index.mjs +5 -0
  28. package/dist/esm/translateDoc/translateDoc.mjs +72 -0
  29. package/dist/esm/translateDoc/translateDoc.mjs.map +1 -0
  30. package/dist/esm/translateDoc/translateFile.mjs +102 -0
  31. package/dist/esm/translateDoc/translateFile.mjs.map +1 -0
  32. package/dist/esm/translateDoc/types.mjs +0 -0
  33. package/dist/esm/translateDoc/validation.mjs +47 -0
  34. package/dist/esm/translateDoc/validation.mjs.map +1 -0
  35. package/dist/esm/translation-alignment/planActions.mjs +2 -4
  36. package/dist/esm/translation-alignment/planActions.mjs.map +1 -1
  37. package/dist/esm/translation-alignment/segmentDocument.mjs +35 -101
  38. package/dist/esm/translation-alignment/segmentDocument.mjs.map +1 -1
  39. package/dist/types/cli.d.ts.map +1 -1
  40. package/dist/types/index.d.ts +3 -3
  41. package/dist/types/{reviewDoc.d.ts → reviewDoc/reviewDoc.d.ts} +1 -1
  42. package/dist/types/reviewDoc/reviewDoc.d.ts.map +1 -0
  43. package/dist/types/{reviewDocBlockAware.d.ts → reviewDoc/reviewDocBlockAware.d.ts} +2 -2
  44. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts.map +1 -0
  45. package/dist/types/translateDoc/index.d.ts +5 -0
  46. package/dist/types/translateDoc/translateDoc.d.ts +21 -0
  47. package/dist/types/translateDoc/translateDoc.d.ts.map +1 -0
  48. package/dist/types/translateDoc/translateFile.d.ts +21 -0
  49. package/dist/types/translateDoc/translateFile.d.ts.map +1 -0
  50. package/dist/types/translateDoc/types.d.ts +47 -0
  51. package/dist/types/translateDoc/types.d.ts.map +1 -0
  52. package/dist/types/translateDoc/validation.d.ts +16 -0
  53. package/dist/types/translateDoc/validation.d.ts.map +1 -0
  54. package/dist/types/translation-alignment/planActions.d.ts +2 -2
  55. package/dist/types/translation-alignment/planActions.d.ts.map +1 -1
  56. package/dist/types/translation-alignment/rebuildDocument.d.ts.map +1 -1
  57. package/dist/types/translation-alignment/segmentDocument.d.ts.map +1 -1
  58. package/package.json +11 -11
  59. package/dist/cjs/reviewDoc.cjs.map +0 -1
  60. package/dist/cjs/reviewDocBlockAware.cjs.map +0 -1
  61. package/dist/cjs/translateDoc.cjs +0 -163
  62. package/dist/cjs/translateDoc.cjs.map +0 -1
  63. package/dist/esm/reviewDoc.mjs.map +0 -1
  64. package/dist/esm/reviewDocBlockAware.mjs.map +0 -1
  65. package/dist/esm/translateDoc.mjs +0 -160
  66. package/dist/esm/translateDoc.mjs.map +0 -1
  67. package/dist/types/reviewDoc.d.ts.map +0 -1
  68. package/dist/types/reviewDocBlockAware.d.ts.map +0 -1
  69. package/dist/types/translateDoc.d.ts +0 -56
  70. package/dist/types/translateDoc.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateFile.cjs","names":["performance","chunkText","ANSIColors","readAsset","translatedParts: string[]","chunkInference","sanitizeChunk","fixChunkStartEndChars","validateTranslation","error: any"],"sources":["../../../src/translateDoc/translateFile.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, relative } from 'node:path';\nimport { performance } from 'node:perf_hooks';\nimport { readAsset } from 'utils:asset';\nimport { formatLocale, formatPath } from '@intlayer/chokidar';\nimport {\n ANSIColors,\n colon,\n colorize,\n colorizeNumber,\n getAppLogger,\n retryManager,\n} from '@intlayer/config';\nimport { chunkText } from '../utils/calculateChunks';\nimport { chunkInference } from '../utils/chunkInference';\nimport { fixChunkStartEndChars } from '../utils/fixChunkStartEndChars';\nimport type { TranslateFileOptions } from './types';\nimport { sanitizeChunk, validateTranslation } from './validation';\n\nexport const translateFile = async ({\n baseFilePath,\n outputFilePath,\n locale,\n baseLocale,\n configuration,\n errorState,\n aiOptions,\n customInstructions,\n aiClient,\n aiConfig,\n flushStrategy = 'incremental',\n onChunkReceive,\n limit, // The Global Limiter\n}: TranslateFileOptions): Promise<string | null> => {\n if (errorState.shouldStop) return null;\n\n const appLogger = getAppLogger(configuration, { config: { prefix: '' } });\n const fileStartTime = performance.now();\n\n try {\n const fileContent = await readFile(baseFilePath, 'utf-8');\n const chunks = chunkText(fileContent);\n const totalChunks = chunks.length;\n\n const filePrefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}] `;\n const filePrefix = `${colon(filePrefixText, { colSize: 40 })}${ANSIColors.RESET}`;\n const prefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}][${formatLocale(locale)}${ANSIColors.GREY_DARK}] `;\n const prefix = `${colon(prefixText, { colSize: 40 })}${ANSIColors.RESET}`;\n\n appLogger(\n `${filePrefix}Split into ${colorizeNumber(totalChunks)} chunks. Queuing...`\n );\n\n const basePrompt = readAsset('./prompts/TRANSLATE_PROMPT.md', 'utf-8')\n .replaceAll('{{localeName}}', `${formatLocale(locale, false)}`)\n .replaceAll('{{baseLocaleName}}', `${formatLocale(baseLocale, false)}`)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const translatedParts: string[] = new Array(totalChunks).fill('');\n\n // Fallback if no limiter is provided (runs immediately)\n const runTask = limit ?? ((fn) => fn());\n\n // MAP CHUNKS TO GLOBAL TASKS\n // This pushes ALL chunks for this file into the Global Queue immediately.\n // They will execute whenever the global concurrency slots open up.\n const tasks = chunks.map((chunk, i) =>\n runTask(async () => {\n if (errorState.shouldStop) return null;\n\n const chunkLogger = getAppLogger(configuration, {\n config: {\n prefix: `${prefix} ${ANSIColors.GREY_DARK}[${i + 1}/${totalChunks}] ${ANSIColors.RESET}`,\n },\n });\n\n const chunkStartTime = performance.now();\n const isFirstChunk = i === 0;\n const fileToTranslateCurrentChunk = chunk.content;\n\n // Context Preparation\n const getPrevChunkPrompt = () =>\n `>>> CONTEXT: PREVIOUS SOURCE CONTENT <<<\\n\\`\\`\\`\\n` +\n (chunks[i - 1]?.content ?? '') +\n `\\n\\`\\`\\`\\n>>> END PREVIOUS CONTEXT <<<`;\n\n const getBaseChunkContextPrompt = () =>\n `>>> CONTEXT: NEXT CONTENT <<<\\n\\`\\`\\`\\n` +\n (chunks[i + 1]?.content ?? '') +\n `\\n\\`\\`\\`\\n>>> END NEXT CONTEXT <<<`;\n\n chunkLogger('Process started');\n\n const chunkTranslation = retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n ...(chunks[i + 1]\n ? [\n {\n role: 'system',\n content: getBaseChunkContextPrompt(),\n } as const,\n ]\n : []),\n ...(isFirstChunk\n ? []\n : [{ role: 'system', content: getPrevChunkPrompt() } as const]),\n {\n role: 'system',\n content: [\n `You are translating TARGET CHUNK (${i + 1}/${totalChunks}).`,\n `Translate ONLY the target chunk. Preserve frontmatter/code exactly.`,\n ].join('\\n'),\n },\n {\n role: 'user',\n content: `>>> TARGET CHUNK START <<<\\n${fileToTranslateCurrentChunk}\\n>>> TARGET CHUNK END <<<`,\n },\n ],\n aiOptions,\n configuration,\n aiClient,\n aiConfig\n );\n\n let processedChunk = sanitizeChunk(\n result?.fileContent,\n fileToTranslateCurrentChunk\n );\n processedChunk = fixChunkStartEndChars(\n processedChunk,\n fileToTranslateCurrentChunk\n );\n\n const isValid = validateTranslation(\n fileToTranslateCurrentChunk,\n processedChunk,\n chunkLogger\n );\n\n if (!isValid) {\n // Throwing an error here signals retryManager to try again\n throw new Error(\n `Validation failed for chunk ${i + 1}/${totalChunks}`\n );\n }\n\n return { content: processedChunk, tokens: result.tokenUsed };\n });\n\n const { content: translatedChunk, tokens } = await chunkTranslation();\n const chunkEndTime = performance.now();\n const chunkDuration = (chunkEndTime - chunkStartTime).toFixed(0);\n\n // Store Result\n translatedParts[i] = translatedChunk;\n\n if (onChunkReceive) {\n onChunkReceive(translatedChunk, i, totalChunks);\n }\n\n // Incremental Flush Strategy\n if (flushStrategy === 'incremental') {\n const isContiguous = translatedParts\n .slice(0, i + 1)\n .every((p) => p && p !== '');\n\n if (isContiguous) {\n let endIdx = 0;\n while (\n endIdx < totalChunks &&\n translatedParts[endIdx] &&\n translatedParts[endIdx] !== ''\n ) {\n endIdx++;\n }\n const currentContent = translatedParts.slice(0, endIdx).join('');\n // Write asynchronously/sync is fine here as node handles file locks reasonably well for single process\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, currentContent);\n }\n }\n\n chunkLogger(\n [\n `${colorizeNumber(tokens)} tokens used `,\n `${ANSIColors.GREY_DARK}in ${colorizeNumber(chunkDuration)}ms${ANSIColors.RESET}`,\n ].join('')\n );\n })\n );\n\n // Wait for all chunks for this specific file/locale to finish\n await Promise.all(tasks);\n\n // Final Flush\n const fullContent = translatedParts.join('');\n if (flushStrategy === 'end' || flushStrategy === 'incremental') {\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, fullContent);\n }\n\n const fileEndTime = performance.now();\n const totalDuration = ((fileEndTime - fileStartTime) / 1000).toFixed(2);\n const relativePath = relative(\n configuration.content.baseDir,\n outputFilePath\n );\n\n appLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(relativePath)} completed in ${colorizeNumber(totalDuration)}s.`\n );\n\n return fullContent;\n } catch (error: any) {\n errorState.count++;\n const errorMessage = error?.message ?? JSON.stringify(error);\n appLogger(`${colorize('✖', ANSIColors.RED)} Error: ${errorMessage}`);\n if (errorState.count >= errorState.maxErrors) errorState.shouldStop = true;\n return null;\n }\n};\n"],"mappings":";;;;;;;;;;;;;;AAoBA,MAAa,gBAAgB,OAAO,EAClC,cACA,gBACA,QACA,YACA,eACA,YACA,WACA,oBACA,UACA,UACA,gBAAgB,eAChB,gBACA,YACkD;AAClD,KAAI,WAAW,WAAY,QAAO;CAElC,MAAM,+CAAyB,eAAe,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC;CACzE,MAAM,gBAAgBA,4BAAY,KAAK;AAEvC,KAAI;EAEF,MAAM,SAASC,wCADK,qCAAe,cAAc,QAAQ,CACpB;EACrC,MAAM,cAAc,OAAO;EAG3B,MAAM,aAAa,+BADI,GAAGC,4BAAW,UAAU,sCAAc,aAAa,GAAGA,4BAAW,UAAU,KACtD,EAAE,SAAS,IAAI,CAAC,GAAGA,4BAAW;EAE1E,MAAM,SAAS,+BADI,GAAGA,4BAAW,UAAU,sCAAc,aAAa,GAAGA,4BAAW,UAAU,yCAAiB,OAAO,GAAGA,4BAAW,UAAU,KAC1G,EAAE,SAAS,IAAI,CAAC,GAAGA,4BAAW;AAElE,YACE,GAAG,WAAW,kDAA4B,YAAY,CAAC,qBACxD;EAED,MAAM,aAAaC,+BAAU,iCAAiC,QAAQ,CACnE,WAAW,kBAAkB,wCAAgB,QAAQ,MAAM,GAAG,CAC9D,WAAW,sBAAsB,wCAAgB,YAAY,MAAM,GAAG,CACtE,QAAQ,0BAA0B,WAAW,sBAAsB,IAAI,CACvE,QAAQ,0BAA0B,sBAAsB,IAAI;EAE/D,MAAMC,kBAA4B,IAAI,MAAM,YAAY,CAAC,KAAK,GAAG;EAGjE,MAAM,UAAU,WAAW,OAAO,IAAI;EAKtC,MAAM,QAAQ,OAAO,KAAK,OAAO,MAC/B,QAAQ,YAAY;AAClB,OAAI,WAAW,WAAY,QAAO;GAElC,MAAM,iDAA2B,eAAe,EAC9C,QAAQ,EACN,QAAQ,GAAG,OAAO,IAAIF,4BAAW,UAAU,GAAG,IAAI,EAAE,GAAG,YAAY,IAAIA,4BAAW,SACnF,EACF,CAAC;GAEF,MAAM,iBAAiBF,4BAAY,KAAK;GACxC,MAAM,eAAe,MAAM;GAC3B,MAAM,8BAA8B,MAAM;GAG1C,MAAM,2BACJ,wDACC,OAAO,IAAI,IAAI,WAAW,MAC3B;GAEF,MAAM,kCACJ,6CACC,OAAO,IAAI,IAAI,WAAW,MAC3B;AAEF,eAAY,kBAAkB;GA4D9B,MAAM,EAAE,SAAS,iBAAiB,WAAW,yCA1DP,YAAY;IAChD,MAAM,SAAS,MAAMK,4CACnB;KACE;MAAE,MAAM;MAAU,SAAS;MAAY;KACvC,GAAI,OAAO,IAAI,KACX,CACE;MACE,MAAM;MACN,SAAS,2BAA2B;MACrC,CACF,GACD,EAAE;KACN,GAAI,eACA,EAAE,GACF,CAAC;MAAE,MAAM;MAAU,SAAS,oBAAoB;MAAE,CAAU;KAChE;MACE,MAAM;MACN,SAAS,CACP,qCAAqC,IAAI,EAAE,GAAG,YAAY,KAC1D,sEACD,CAAC,KAAK,KAAK;MACb;KACD;MACE,MAAM;MACN,SAAS,+BAA+B,4BAA4B;MACrE;KACF,EACD,WACA,eACA,UACA,SACD;IAED,IAAI,iBAAiBC,8CACnB,QAAQ,aACR,4BACD;AACD,qBAAiBC,0DACf,gBACA,4BACD;AAQD,QAAI,CANYC,oDACd,6BACA,gBACA,YACD,CAIC,OAAM,IAAI,MACR,+BAA+B,IAAI,EAAE,GAAG,cACzC;AAGH,WAAO;KAAE,SAAS;KAAgB,QAAQ,OAAO;KAAW;KAC5D,EAEmE;GAErE,MAAM,iBADeR,4BAAY,KAAK,GACA,gBAAgB,QAAQ,EAAE;AAGhE,mBAAgB,KAAK;AAErB,OAAI,eACF,gBAAe,iBAAiB,GAAG,YAAY;AAIjD,OAAI,kBAAkB,eAKpB;QAJqB,gBAClB,MAAM,GAAG,IAAI,EAAE,CACf,OAAO,MAAM,KAAK,MAAM,GAAG,EAEZ;KAChB,IAAI,SAAS;AACb,YACE,SAAS,eACT,gBAAgB,WAChB,gBAAgB,YAAY,GAE5B;KAEF,MAAM,iBAAiB,gBAAgB,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG;AAEhE,mDAAkB,eAAe,EAAE,EAAE,WAAW,MAAM,CAAC;AACvD,gCAAc,gBAAgB,eAAe;;;AAIjD,eACE,CACE,wCAAkB,OAAO,CAAC,gBAC1B,GAAGE,4BAAW,UAAU,0CAAoB,cAAc,CAAC,IAAIA,4BAAW,QAC3E,CAAC,KAAK,GAAG,CACX;IACD,CACH;AAGD,QAAM,QAAQ,IAAI,MAAM;EAGxB,MAAM,cAAc,gBAAgB,KAAK,GAAG;AAC5C,MAAI,kBAAkB,SAAS,kBAAkB,eAAe;AAC9D,iDAAkB,eAAe,EAAE,EAAE,WAAW,MAAM,CAAC;AACvD,8BAAc,gBAAgB,YAAY;;EAI5C,MAAM,kBADcF,4BAAY,KAAK,GACC,iBAAiB,KAAM,QAAQ,EAAE;EACvE,MAAM,uCACJ,cAAc,QAAQ,SACtB,eACD;AAED,YACE,kCAAY,KAAKE,4BAAW,MAAM,CAAC,2CAAmB,aAAa,CAAC,qDAA+B,cAAc,CAAC,IACnH;AAED,SAAO;UACAO,OAAY;AACnB,aAAW;EACX,MAAM,eAAe,OAAO,WAAW,KAAK,UAAU,MAAM;AAC5D,YAAU,kCAAY,KAAKP,4BAAW,IAAI,CAAC,UAAU,eAAe;AACpE,MAAI,WAAW,SAAS,WAAW,UAAW,YAAW,aAAa;AACtE,SAAO"}
File without changes
@@ -0,0 +1,49 @@
1
+
2
+ //#region src/translateDoc/validation.ts
3
+ /**
4
+ * Validates that the translated content matches the structure of the original.
5
+ * Throws an error if a mismatch is found, triggering a retry.
6
+ */
7
+ const validateTranslation = (original, translated, logger) => {
8
+ const errors = [];
9
+ if (original.trimStart().startsWith("---")) {
10
+ if (!translated.trimStart().startsWith("---")) errors.push("YAML Frontmatter missing: Input starts with \"---\", output does not.");
11
+ const originalDashes = (original.match(/^---$/gm) || []).length;
12
+ const translatedDashes = (translated.match(/^---$/gm) || []).length;
13
+ if (originalDashes >= 2 && translatedDashes < 2) errors.push("YAML Frontmatter unclosed: Input has closing \"---\", output is missing it.");
14
+ }
15
+ const fenceRegex = /^\s*```/gm;
16
+ const originalFences = (original.match(fenceRegex) || []).length;
17
+ const translatedFences = (translated.match(fenceRegex) || []).length;
18
+ if (originalFences !== translatedFences) errors.push(`Code fence mismatch: Input has ${originalFences}, output has ${translatedFences}`);
19
+ const ratio = translated.length / (original.length || 1);
20
+ const isTooLong = ratio > 2.5;
21
+ const isSignificantLength = original.length > 50;
22
+ if (isTooLong && isSignificantLength) errors.push(`Length deviation: Output is ${translated.length} chars vs Input ${original.length} (${ratio.toFixed(1)}x). Likely included context.`);
23
+ const originalLines = original.split("\n").length;
24
+ const translatedLines = translated.split("\n").length;
25
+ if (originalLines > 5) {
26
+ if (translatedLines < originalLines * .4) errors.push(`Line count deviation: Output has ${translatedLines} lines, Input has ${originalLines}. Likely content deletion.`);
27
+ }
28
+ if (errors.length > 0) {
29
+ logger(`Validation Failed: ${errors.join(", ")}`);
30
+ return false;
31
+ }
32
+ return true;
33
+ };
34
+ /**
35
+ * Clean common AI artifacts
36
+ */
37
+ const sanitizeChunk = (translated, original) => {
38
+ let cleaned = translated;
39
+ const match = cleaned.match(/^```(?:markdown|md|txt)?\n([\s\S]*?)\n```$/i);
40
+ if (match) cleaned = match[1];
41
+ if (!original.startsWith("\n") && cleaned.startsWith("\n")) cleaned = cleaned.replace(/^\n+/, "");
42
+ if (!original.startsWith(" ") && cleaned.startsWith(" ")) cleaned = cleaned.trimStart();
43
+ return cleaned;
44
+ };
45
+
46
+ //#endregion
47
+ exports.sanitizeChunk = sanitizeChunk;
48
+ exports.validateTranslation = validateTranslation;
49
+ //# sourceMappingURL=validation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.cjs","names":["errors: string[]"],"sources":["../../../src/translateDoc/validation.ts"],"sourcesContent":["import type { Logger } from '@intlayer/config';\n\n/**\n * Validates that the translated content matches the structure of the original.\n * Throws an error if a mismatch is found, triggering a retry.\n */\nexport const validateTranslation = (\n original: string,\n translated: string,\n logger: Logger\n): boolean => {\n const errors: string[] = [];\n\n // YAML Frontmatter Integrity (CRITICAL)\n if (original.trimStart().startsWith('---')) {\n if (!translated.trimStart().startsWith('---')) {\n errors.push(\n 'YAML Frontmatter missing: Input starts with \"---\", output does not.'\n );\n }\n const originalDashes = (original.match(/^---$/gm) || []).length;\n const translatedDashes = (translated.match(/^---$/gm) || []).length;\n if (originalDashes >= 2 && translatedDashes < 2) {\n errors.push(\n 'YAML Frontmatter unclosed: Input has closing \"---\", output is missing it.'\n );\n }\n }\n\n // Code Fence Check\n const fenceRegex = /^\\s*```/gm;\n const originalFences = (original.match(fenceRegex) || []).length;\n const translatedFences = (translated.match(fenceRegex) || []).length;\n\n if (originalFences !== translatedFences) {\n errors.push(\n `Code fence mismatch: Input has ${originalFences}, output has ${translatedFences}`\n );\n }\n\n // Length/Duplication Check\n const ratio = translated.length / (original.length || 1);\n const isTooLong = ratio > 2.5;\n const isSignificantLength = original.length > 50;\n\n if (isTooLong && isSignificantLength) {\n errors.push(\n `Length deviation: Output is ${translated.length} chars vs Input ${original.length} (${ratio.toFixed(1)}x). Likely included context.`\n );\n }\n\n // Line Count Heuristic\n const originalLines = original.split('\\n').length;\n const translatedLines = translated.split('\\n').length;\n\n if (originalLines > 5) {\n if (translatedLines < originalLines * 0.4) {\n errors.push(\n `Line count deviation: Output has ${translatedLines} lines, Input has ${originalLines}. Likely content deletion.`\n );\n }\n }\n\n if (errors.length > 0) {\n logger(`Validation Failed: ${errors.join(', ')}`);\n return false;\n }\n\n return true;\n};\n\n/**\n * Clean common AI artifacts\n */\nexport const sanitizeChunk = (translated: string, original: string): string => {\n let cleaned = translated;\n const wrapRegex = /^```(?:markdown|md|txt)?\\n([\\s\\S]*?)\\n```$/i;\n const match = cleaned.match(wrapRegex);\n if (match) cleaned = match[1];\n\n if (!original.startsWith('\\n') && cleaned.startsWith('\\n')) {\n cleaned = cleaned.replace(/^\\n+/, '');\n }\n if (!original.startsWith(' ') && cleaned.startsWith(' ')) {\n cleaned = cleaned.trimStart();\n }\n return cleaned;\n};\n"],"mappings":";;;;;;AAMA,MAAa,uBACX,UACA,YACA,WACY;CACZ,MAAMA,SAAmB,EAAE;AAG3B,KAAI,SAAS,WAAW,CAAC,WAAW,MAAM,EAAE;AAC1C,MAAI,CAAC,WAAW,WAAW,CAAC,WAAW,MAAM,CAC3C,QAAO,KACL,wEACD;EAEH,MAAM,kBAAkB,SAAS,MAAM,UAAU,IAAI,EAAE,EAAE;EACzD,MAAM,oBAAoB,WAAW,MAAM,UAAU,IAAI,EAAE,EAAE;AAC7D,MAAI,kBAAkB,KAAK,mBAAmB,EAC5C,QAAO,KACL,8EACD;;CAKL,MAAM,aAAa;CACnB,MAAM,kBAAkB,SAAS,MAAM,WAAW,IAAI,EAAE,EAAE;CAC1D,MAAM,oBAAoB,WAAW,MAAM,WAAW,IAAI,EAAE,EAAE;AAE9D,KAAI,mBAAmB,iBACrB,QAAO,KACL,kCAAkC,eAAe,eAAe,mBACjE;CAIH,MAAM,QAAQ,WAAW,UAAU,SAAS,UAAU;CACtD,MAAM,YAAY,QAAQ;CAC1B,MAAM,sBAAsB,SAAS,SAAS;AAE9C,KAAI,aAAa,oBACf,QAAO,KACL,+BAA+B,WAAW,OAAO,kBAAkB,SAAS,OAAO,IAAI,MAAM,QAAQ,EAAE,CAAC,8BACzG;CAIH,MAAM,gBAAgB,SAAS,MAAM,KAAK,CAAC;CAC3C,MAAM,kBAAkB,WAAW,MAAM,KAAK,CAAC;AAE/C,KAAI,gBAAgB,GAClB;MAAI,kBAAkB,gBAAgB,GACpC,QAAO,KACL,oCAAoC,gBAAgB,oBAAoB,cAAc,4BACvF;;AAIL,KAAI,OAAO,SAAS,GAAG;AACrB,SAAO,sBAAsB,OAAO,KAAK,KAAK,GAAG;AACjD,SAAO;;AAGT,QAAO;;;;;AAMT,MAAa,iBAAiB,YAAoB,aAA6B;CAC7E,IAAI,UAAU;CAEd,MAAM,QAAQ,QAAQ,MADJ,8CACoB;AACtC,KAAI,MAAO,WAAU,MAAM;AAE3B,KAAI,CAAC,SAAS,WAAW,KAAK,IAAI,QAAQ,WAAW,KAAK,CACxD,WAAU,QAAQ,QAAQ,QAAQ,GAAG;AAEvC,KAAI,CAAC,SAAS,WAAW,IAAI,IAAI,QAAQ,WAAW,IAAI,CACtD,WAAU,QAAQ,WAAW;AAE/B,QAAO"}
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region src/translation-alignment/planActions.ts
3
- const planAlignmentActions = (alignment, changedEnglishBlockIndexes, similarityOptions) => {
3
+ const planAlignmentActions = (alignment, changedEnglishBlockIndexes) => {
4
4
  const actions = [];
5
5
  const seenFrench = /* @__PURE__ */ new Set();
6
6
  alignment.forEach((pair) => {
@@ -24,9 +24,7 @@ const planAlignmentActions = (alignment, changedEnglishBlockIndexes, similarityO
24
24
  return;
25
25
  }
26
26
  if (englishIndex >= 0 && frenchIndex !== null) {
27
- const isChanged = changedEnglishBlockIndexes.has(englishIndex);
28
- const isHighSimilarity = pair.similarityScore >= similarityOptions.minimumMatchForReuse;
29
- if (!isChanged && isHighSimilarity) actions.push({
27
+ if (!changedEnglishBlockIndexes.has(englishIndex)) actions.push({
30
28
  kind: "reuse",
31
29
  englishIndex,
32
30
  frenchIndex
@@ -1 +1 @@
1
- {"version":3,"file":"planActions.cjs","names":["actions: PlannedAction[]"],"sources":["../../../src/translation-alignment/planActions.ts"],"sourcesContent":["import type {\n AlignmentPair,\n AlignmentPlan,\n PlannedAction,\n SimilarityOptions,\n} from './types';\n\nexport const planAlignmentActions = (\n alignment: AlignmentPair[],\n changedEnglishBlockIndexes: Set<number>,\n similarityOptions: SimilarityOptions\n): AlignmentPlan => {\n const actions: PlannedAction[] = [];\n const seenFrench = new Set<number>();\n\n alignment.forEach((pair) => {\n const englishIndex = pair.englishIndex;\n const frenchIndex = pair.frenchIndex;\n\n if (englishIndex === -1 && frenchIndex !== null) {\n // french only -> delete\n if (!seenFrench.has(frenchIndex)) {\n actions.push({ kind: 'delete', frenchIndex });\n seenFrench.add(frenchIndex);\n }\n return;\n }\n\n if (englishIndex >= 0 && frenchIndex === null) {\n // new english block\n actions.push({ kind: 'insert_new', englishIndex });\n return;\n }\n\n if (englishIndex >= 0 && frenchIndex !== null) {\n // matched pair\n const isChanged = changedEnglishBlockIndexes.has(englishIndex);\n const isHighSimilarity =\n pair.similarityScore >= similarityOptions.minimumMatchForReuse;\n\n if (!isChanged && isHighSimilarity) {\n actions.push({ kind: 'reuse', englishIndex, frenchIndex });\n } else {\n actions.push({ kind: 'review', englishIndex, frenchIndex });\n }\n seenFrench.add(frenchIndex);\n return;\n }\n });\n\n return { actions };\n};\n"],"mappings":";;AAOA,MAAa,wBACX,WACA,4BACA,sBACkB;CAClB,MAAMA,UAA2B,EAAE;CACnC,MAAM,6BAAa,IAAI,KAAa;AAEpC,WAAU,SAAS,SAAS;EAC1B,MAAM,eAAe,KAAK;EAC1B,MAAM,cAAc,KAAK;AAEzB,MAAI,iBAAiB,MAAM,gBAAgB,MAAM;AAE/C,OAAI,CAAC,WAAW,IAAI,YAAY,EAAE;AAChC,YAAQ,KAAK;KAAE,MAAM;KAAU;KAAa,CAAC;AAC7C,eAAW,IAAI,YAAY;;AAE7B;;AAGF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;AAE7C,WAAQ,KAAK;IAAE,MAAM;IAAc;IAAc,CAAC;AAClD;;AAGF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;GAE7C,MAAM,YAAY,2BAA2B,IAAI,aAAa;GAC9D,MAAM,mBACJ,KAAK,mBAAmB,kBAAkB;AAE5C,OAAI,CAAC,aAAa,iBAChB,SAAQ,KAAK;IAAE,MAAM;IAAS;IAAc;IAAa,CAAC;OAE1D,SAAQ,KAAK;IAAE,MAAM;IAAU;IAAc;IAAa,CAAC;AAE7D,cAAW,IAAI,YAAY;AAC3B;;GAEF;AAEF,QAAO,EAAE,SAAS"}
1
+ {"version":3,"file":"planActions.cjs","names":["actions: PlannedAction[]"],"sources":["../../../src/translation-alignment/planActions.ts"],"sourcesContent":["import type { AlignmentPair, AlignmentPlan, PlannedAction } from './types';\n\nexport const planAlignmentActions = (\n alignment: AlignmentPair[],\n changedEnglishBlockIndexes: Set<number>\n): AlignmentPlan => {\n const actions: PlannedAction[] = [];\n const seenFrench = new Set<number>();\n\n alignment.forEach((pair) => {\n const englishIndex = pair.englishIndex;\n const frenchIndex = pair.frenchIndex;\n\n // Case 1: Deletion (Exists in FR, not in EN)\n if (englishIndex === -1 && frenchIndex !== null) {\n if (!seenFrench.has(frenchIndex)) {\n actions.push({ kind: 'delete', frenchIndex });\n seenFrench.add(frenchIndex);\n }\n return;\n }\n\n // Case 2: New Insertion (Exists in EN, not in FR)\n if (englishIndex >= 0 && frenchIndex === null) {\n actions.push({ kind: 'insert_new', englishIndex });\n return;\n }\n\n // Case 3: Alignment (Exists in both)\n if (englishIndex >= 0 && frenchIndex !== null) {\n const isChanged = changedEnglishBlockIndexes.has(englishIndex);\n\n // If the block is NOT marked as changed by Git, we REUSE it.\n // We assume the existing translation is correct because the source hasn't been touched.\n // We ignore 'similarityScore' here because EN vs UK text will always have low similarity.\n if (!isChanged) {\n actions.push({ kind: 'reuse', englishIndex, frenchIndex });\n } else {\n // If the block IS changed, we normally Review.\n // OPTIONAL: You could add a check here for 'similarityScore > 0.99'\n // to detect whitespace-only changes, but generally, if Git says changed, we Review.\n actions.push({ kind: 'review', englishIndex, frenchIndex });\n }\n\n seenFrench.add(frenchIndex);\n return;\n }\n });\n\n return { actions };\n};\n"],"mappings":";;AAEA,MAAa,wBACX,WACA,+BACkB;CAClB,MAAMA,UAA2B,EAAE;CACnC,MAAM,6BAAa,IAAI,KAAa;AAEpC,WAAU,SAAS,SAAS;EAC1B,MAAM,eAAe,KAAK;EAC1B,MAAM,cAAc,KAAK;AAGzB,MAAI,iBAAiB,MAAM,gBAAgB,MAAM;AAC/C,OAAI,CAAC,WAAW,IAAI,YAAY,EAAE;AAChC,YAAQ,KAAK;KAAE,MAAM;KAAU;KAAa,CAAC;AAC7C,eAAW,IAAI,YAAY;;AAE7B;;AAIF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;AAC7C,WAAQ,KAAK;IAAE,MAAM;IAAc;IAAc,CAAC;AAClD;;AAIF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;AAM7C,OAAI,CALc,2BAA2B,IAAI,aAAa,CAM5D,SAAQ,KAAK;IAAE,MAAM;IAAS;IAAc;IAAa,CAAC;OAK1D,SAAQ,KAAK;IAAE,MAAM;IAAU;IAAc;IAAa,CAAC;AAG7D,cAAW,IAAI,YAAY;AAC3B;;GAEF;AAEF,QAAO,EAAE,SAAS"}
@@ -3,127 +3,61 @@
3
3
  const isBlankLine = (line) => line.trim().length === 0;
4
4
  const isFencedCodeDelimiter = (line) => /^\s*```/.test(line);
5
5
  const isHeading = (line) => /^\s*#{1,6}\s+/.test(line);
6
- const isHorizontalRule = (line) => /^(\s*[-*_]){3,}\s*$/.test(line);
7
- const isListItem = (line) => /^\s*([-*+]\s+|\d+\.[\t\s]+)/.test(line);
8
- const isBlockquote = (line) => /^\s*>\s?/.test(line);
9
- const isTableLike = (line) => /\|/.test(line) && !isCodeFenceStart(line);
10
- const isCodeFenceStart = (line) => /^\s*```/.test(line);
6
+ const isFrontmatterDelimiter = (line) => /^\s*---\s*$/.test(line);
11
7
  const trimTrailingNewlines = (text) => text.replace(/\n+$/g, "\n");
12
8
  const segmentDocument = (text) => {
13
9
  const lines = text.split("\n");
14
10
  const blocks = [];
15
11
  let index = 0;
12
+ let insideCodeBlock = false;
13
+ let currentSectionLines = [];
14
+ let currentSectionStartLine = 1;
15
+ const flushCurrentSection = (endIndex) => {
16
+ if (currentSectionLines.length > 0) {
17
+ const rawContent = currentSectionLines.join("\n");
18
+ if (rawContent.trim().length > 0) blocks.push({
19
+ type: "paragraph",
20
+ content: `${trimTrailingNewlines(rawContent)}\n`,
21
+ lineStart: currentSectionStartLine,
22
+ lineEnd: endIndex
23
+ });
24
+ currentSectionLines = [];
25
+ }
26
+ };
16
27
  while (index < lines.length) {
17
- const startIndex = index;
18
28
  const currentLine = lines[index];
19
- if (isFencedCodeDelimiter(currentLine)) {
29
+ if (blocks.length === 0 && isFrontmatterDelimiter(currentLine)) {
30
+ const startLine = index + 1;
20
31
  const contentLines = [currentLine];
21
- index += 1;
22
- while (index < lines.length && !isFencedCodeDelimiter(lines[index])) {
23
- contentLines.push(lines[index]);
24
- index += 1;
25
- }
26
- if (index < lines.length) {
27
- contentLines.push(lines[index]);
28
- index += 1;
29
- }
30
- blocks.push({
31
- type: "code_block",
32
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
33
- lineStart: startIndex + 1,
34
- lineEnd: index
35
- });
36
- continue;
37
- }
38
- if (isHorizontalRule(currentLine)) {
39
- blocks.push({
40
- type: "horizontal_rule",
41
- content: `${currentLine}\n`,
42
- lineStart: startIndex + 1,
43
- lineEnd: startIndex + 1
44
- });
45
- index += 1;
46
- continue;
47
- }
48
- if (isHeading(currentLine)) {
49
- blocks.push({
50
- type: "heading",
51
- content: `${currentLine}\n`,
52
- lineStart: startIndex + 1,
53
- lineEnd: startIndex + 1
54
- });
55
- index += 1;
56
- continue;
57
- }
58
- if (isListItem(currentLine)) {
59
- const contentLines = [];
60
- while (index < lines.length && (isListItem(lines[index]) || !isBlankLine(lines[index]) && /^\s{2,}/.test(lines[index]))) {
61
- contentLines.push(lines[index]);
62
- index += 1;
63
- }
64
- blocks.push({
65
- type: "list_item",
66
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
67
- lineStart: startIndex + 1,
68
- lineEnd: index
69
- });
70
- continue;
71
- }
72
- if (isBlockquote(currentLine)) {
73
- const contentLines = [];
74
- while (index < lines.length && (isBlockquote(lines[index]) || !isBlankLine(lines[index]))) {
32
+ index++;
33
+ while (index < lines.length && !isFrontmatterDelimiter(lines[index])) {
75
34
  contentLines.push(lines[index]);
76
- index += 1;
35
+ index++;
77
36
  }
78
- blocks.push({
79
- type: "blockquote",
80
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
81
- lineStart: startIndex + 1,
82
- lineEnd: index
83
- });
84
- continue;
85
- }
86
- if (isTableLike(currentLine)) {
87
- const contentLines = [];
88
- while (index < lines.length && /\|/.test(lines[index]) && !isBlankLine(lines[index])) {
37
+ if (index < lines.length && isFrontmatterDelimiter(lines[index])) {
89
38
  contentLines.push(lines[index]);
90
- index += 1;
91
- }
92
- blocks.push({
93
- type: "table",
94
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
95
- lineStart: startIndex + 1,
96
- lineEnd: index
97
- });
98
- continue;
99
- }
100
- if (!isBlankLine(currentLine)) {
101
- const contentLines = [];
102
- while (index < lines.length && !isBlankLine(lines[index])) {
103
- if (isHeading(lines[index]) || isFencedCodeDelimiter(lines[index]) || isHorizontalRule(lines[index]) || isListItem(lines[index]) || isBlockquote(lines[index]) || isTableLike(lines[index])) break;
104
- contentLines.push(lines[index]);
105
- index += 1;
106
- }
107
- if (index < lines.length && isBlankLine(lines[index])) {
108
- contentLines.push(lines[index]);
109
- index += 1;
39
+ index++;
110
40
  }
111
41
  blocks.push({
112
42
  type: "paragraph",
113
43
  content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
114
- lineStart: startIndex + 1,
44
+ lineStart: startLine,
115
45
  lineEnd: index
116
46
  });
117
47
  continue;
118
48
  }
119
- blocks.push({
120
- type: "unknown",
121
- content: `${currentLine}\n`,
122
- lineStart: startIndex + 1,
123
- lineEnd: startIndex + 1
124
- });
125
- index += 1;
49
+ if (isFencedCodeDelimiter(currentLine)) insideCodeBlock = !insideCodeBlock;
50
+ if (!insideCodeBlock && isHeading(currentLine)) {
51
+ if (currentSectionLines.length > 0) flushCurrentSection(index);
52
+ currentSectionStartLine = index + 1;
53
+ currentSectionLines = [currentLine];
54
+ } else {
55
+ if (currentSectionLines.length === 0 && !isBlankLine(currentLine)) currentSectionStartLine = index + 1;
56
+ currentSectionLines.push(currentLine);
57
+ }
58
+ index++;
126
59
  }
60
+ flushCurrentSection(index);
127
61
  return blocks;
128
62
  };
129
63
 
@@ -1 +1 @@
1
- {"version":3,"file":"segmentDocument.cjs","names":["blocks: Block[]","contentLines: string[]"],"sources":["../../../src/translation-alignment/segmentDocument.ts"],"sourcesContent":["import type { Block } from './types';\n\nconst isBlankLine = (line: string): boolean => line.trim().length === 0;\n\nconst isFencedCodeDelimiter = (line: string): boolean => /^\\s*```/.test(line);\n\nconst isHeading = (line: string): boolean => /^\\s*#{1,6}\\s+/.test(line);\n\nconst isHorizontalRule = (line: string): boolean =>\n /^(\\s*[-*_]){3,}\\s*$/.test(line);\n\nconst isListItem = (line: string): boolean =>\n /^\\s*([-*+]\\s+|\\d+\\.[\\t\\s]+)/.test(line);\n\nconst isBlockquote = (line: string): boolean => /^\\s*>\\s?/.test(line);\n\nconst isTableLike = (line: string): boolean =>\n /\\|/.test(line) && !isCodeFenceStart(line);\n\nconst isCodeFenceStart = (line: string): boolean => /^\\s*```/.test(line);\n\nconst trimTrailingNewlines = (text: string): string =>\n text.replace(/\\n+$/g, '\\n');\n\nexport const segmentDocument = (text: string): Block[] => {\n const lines = text.split('\\n');\n const blocks: Block[] = [];\n\n let index = 0;\n while (index < lines.length) {\n const startIndex = index;\n const currentLine = lines[index];\n\n // Code block (fenced)\n if (isFencedCodeDelimiter(currentLine)) {\n const contentLines: string[] = [currentLine];\n index += 1;\n while (index < lines.length && !isFencedCodeDelimiter(lines[index])) {\n contentLines.push(lines[index]);\n index += 1;\n }\n if (index < lines.length) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'code_block',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Horizontal rule\n if (isHorizontalRule(currentLine)) {\n blocks.push({\n type: 'horizontal_rule',\n content: `${currentLine}\\n`,\n lineStart: startIndex + 1,\n lineEnd: startIndex + 1,\n });\n index += 1;\n continue;\n }\n\n // Heading\n if (isHeading(currentLine)) {\n blocks.push({\n type: 'heading',\n content: `${currentLine}\\n`,\n lineStart: startIndex + 1,\n lineEnd: startIndex + 1,\n });\n index += 1;\n continue;\n }\n\n // List block (one or more consecutive list items)\n if (isListItem(currentLine)) {\n const contentLines: string[] = [];\n while (\n index < lines.length &&\n (isListItem(lines[index]) ||\n (!isBlankLine(lines[index]) && /^\\s{2,}/.test(lines[index])))\n ) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'list_item',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Blockquote (may span multiple lines)\n if (isBlockquote(currentLine)) {\n const contentLines: string[] = [];\n while (\n index < lines.length &&\n (isBlockquote(lines[index]) || !isBlankLine(lines[index]))\n ) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'blockquote',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Table-like (simple heuristic)\n if (isTableLike(currentLine)) {\n const contentLines: string[] = [];\n while (\n index < lines.length &&\n /\\|/.test(lines[index]) &&\n !isBlankLine(lines[index])\n ) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'table',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Paragraph (gathers until blank line)\n if (!isBlankLine(currentLine)) {\n const contentLines: string[] = [];\n while (index < lines.length && !isBlankLine(lines[index])) {\n // stop if we detect a new structural block start\n if (\n isHeading(lines[index]) ||\n isFencedCodeDelimiter(lines[index]) ||\n isHorizontalRule(lines[index]) ||\n isListItem(lines[index]) ||\n isBlockquote(lines[index]) ||\n isTableLike(lines[index])\n ) {\n break;\n }\n contentLines.push(lines[index]);\n index += 1;\n }\n // consume a single trailing blank line if present\n if (index < lines.length && isBlankLine(lines[index])) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'paragraph',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Blank line outside of a paragraph: keep to preserve spacing minimally\n blocks.push({\n type: 'unknown',\n content: `${currentLine}\\n`,\n lineStart: startIndex + 1,\n lineEnd: startIndex + 1,\n });\n index += 1;\n }\n\n return blocks;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"segmentDocument.cjs","names":["blocks: Block[]","currentSectionLines: string[]","contentLines: string[]"],"sources":["../../../src/translation-alignment/segmentDocument.ts"],"sourcesContent":["import type { Block } from './types';\n\nconst isBlankLine = (line: string): boolean => line.trim().length === 0;\nconst isFencedCodeDelimiter = (line: string): boolean => /^\\s*```/.test(line);\nconst isHeading = (line: string): boolean => /^\\s*#{1,6}\\s+/.test(line);\nconst isFrontmatterDelimiter = (line: string): boolean =>\n /^\\s*---\\s*$/.test(line);\nconst trimTrailingNewlines = (text: string): string =>\n text.replace(/\\n+$/g, '\\n');\n\nexport const segmentDocument = (text: string): Block[] => {\n const lines = text.split('\\n');\n const blocks: Block[] = [];\n\n let index = 0;\n let insideCodeBlock = false;\n\n // Buffers\n let currentSectionLines: string[] = [];\n let currentSectionStartLine = 1;\n\n const flushCurrentSection = (endIndex: number) => {\n if (currentSectionLines.length > 0) {\n // Filter out leading blank lines from the block content to keep it clean,\n // but strictly speaking, we just want to ensure non-empty content.\n const rawContent = currentSectionLines.join('\\n');\n\n if (rawContent.trim().length > 0) {\n blocks.push({\n type: 'paragraph', // Generic type\n content: `${trimTrailingNewlines(rawContent)}\\n`,\n lineStart: currentSectionStartLine,\n lineEnd: endIndex,\n });\n }\n currentSectionLines = [];\n }\n };\n\n while (index < lines.length) {\n const currentLine = lines[index];\n\n // 1. Handle Frontmatter (Must be at start of file)\n if (blocks.length === 0 && isFrontmatterDelimiter(currentLine)) {\n const startLine = index + 1;\n const contentLines: string[] = [currentLine];\n index++;\n\n while (index < lines.length && !isFrontmatterDelimiter(lines[index])) {\n contentLines.push(lines[index]);\n index++;\n }\n\n if (index < lines.length && isFrontmatterDelimiter(lines[index])) {\n contentLines.push(lines[index]);\n index++;\n }\n\n blocks.push({\n type: 'paragraph',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startLine,\n lineEnd: index,\n });\n continue;\n }\n\n // 2. Track Code Blocks (Headers inside code blocks are ignored)\n if (isFencedCodeDelimiter(currentLine)) {\n insideCodeBlock = !insideCodeBlock;\n }\n\n const isHeader = !insideCodeBlock && isHeading(currentLine);\n\n // 3. Split on Headers\n if (isHeader) {\n // If we have accumulated content, flush it as the previous block\n if (currentSectionLines.length > 0) {\n flushCurrentSection(index);\n }\n // Start a new section with this header\n currentSectionStartLine = index + 1;\n currentSectionLines = [currentLine];\n } else {\n // Accumulate content\n if (currentSectionLines.length === 0 && !isBlankLine(currentLine)) {\n currentSectionStartLine = index + 1;\n }\n currentSectionLines.push(currentLine);\n }\n\n index++;\n }\n\n // Flush remaining content\n flushCurrentSection(index);\n\n return blocks;\n};\n"],"mappings":";;AAEA,MAAM,eAAe,SAA0B,KAAK,MAAM,CAAC,WAAW;AACtE,MAAM,yBAAyB,SAA0B,UAAU,KAAK,KAAK;AAC7E,MAAM,aAAa,SAA0B,gBAAgB,KAAK,KAAK;AACvE,MAAM,0BAA0B,SAC9B,cAAc,KAAK,KAAK;AAC1B,MAAM,wBAAwB,SAC5B,KAAK,QAAQ,SAAS,KAAK;AAE7B,MAAa,mBAAmB,SAA0B;CACxD,MAAM,QAAQ,KAAK,MAAM,KAAK;CAC9B,MAAMA,SAAkB,EAAE;CAE1B,IAAI,QAAQ;CACZ,IAAI,kBAAkB;CAGtB,IAAIC,sBAAgC,EAAE;CACtC,IAAI,0BAA0B;CAE9B,MAAM,uBAAuB,aAAqB;AAChD,MAAI,oBAAoB,SAAS,GAAG;GAGlC,MAAM,aAAa,oBAAoB,KAAK,KAAK;AAEjD,OAAI,WAAW,MAAM,CAAC,SAAS,EAC7B,QAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,WAAW,CAAC;IAC7C,WAAW;IACX,SAAS;IACV,CAAC;AAEJ,yBAAsB,EAAE;;;AAI5B,QAAO,QAAQ,MAAM,QAAQ;EAC3B,MAAM,cAAc,MAAM;AAG1B,MAAI,OAAO,WAAW,KAAK,uBAAuB,YAAY,EAAE;GAC9D,MAAM,YAAY,QAAQ;GAC1B,MAAMC,eAAyB,CAAC,YAAY;AAC5C;AAEA,UAAO,QAAQ,MAAM,UAAU,CAAC,uBAAuB,MAAM,OAAO,EAAE;AACpE,iBAAa,KAAK,MAAM,OAAO;AAC/B;;AAGF,OAAI,QAAQ,MAAM,UAAU,uBAAuB,MAAM,OAAO,EAAE;AAChE,iBAAa,KAAK,MAAM,OAAO;AAC/B;;AAGF,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW;IACX,SAAS;IACV,CAAC;AACF;;AAIF,MAAI,sBAAsB,YAAY,CACpC,mBAAkB,CAAC;AAMrB,MAHiB,CAAC,mBAAmB,UAAU,YAAY,EAG7C;AAEZ,OAAI,oBAAoB,SAAS,EAC/B,qBAAoB,MAAM;AAG5B,6BAA0B,QAAQ;AAClC,yBAAsB,CAAC,YAAY;SAC9B;AAEL,OAAI,oBAAoB,WAAW,KAAK,CAAC,YAAY,YAAY,CAC/D,2BAA0B,QAAQ;AAEpC,uBAAoB,KAAK,YAAY;;AAGvC;;AAIF,qBAAoB,MAAM;AAE1B,QAAO"}
package/dist/esm/cli.mjs CHANGED
@@ -12,9 +12,9 @@ import { liveSync } from "./liveSync.mjs";
12
12
  import { pull } from "./pull.mjs";
13
13
  import { push } from "./push/push.mjs";
14
14
  import { pushConfig } from "./pushConfig.mjs";
15
- import { reviewDoc } from "./reviewDoc.mjs";
15
+ import { reviewDoc } from "./reviewDoc/reviewDoc.mjs";
16
16
  import { transform } from "./transform.mjs";
17
- import { translateDoc } from "./translateDoc.mjs";
17
+ import { translateDoc } from "./translateDoc/translateDoc.mjs";
18
18
  import { getParentPackageJSON } from "./utils/getParentPackageJSON.mjs";
19
19
  import { watchContentDeclaration } from "./watch.mjs";
20
20
  import { getConfiguration } from "@intlayer/config";
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["isESModule","pathDirname","gitOptionKeys: (keyof GitOptions)[]","configurationOptionKeys: (keyof ConfigurationOptions)[]","addPrefix: boolean"],"sources":["../../src/cli.ts"],"sourcesContent":["import { dirname as pathDirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AIOptions as BaseAIOptions } from '@intlayer/api';\nimport type { GetConfigurationOptions } from '@intlayer/config';\nimport { getConfiguration } from '@intlayer/config';\nimport { Command } from 'commander';\nimport type {\n DiffMode,\n ListGitFilesOptions,\n} from '../../chokidar/dist/types/listGitFiles';\nimport { login } from './auth/login';\nimport { build } from './build';\nimport { runCI } from './ci';\nimport { getConfig } from './config';\nimport { startEditor } from './editor';\nimport { type FillOptions, fill } from './fill/fill';\nimport { init } from './init';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { listProjectsCommand } from './listProjects';\nimport { liveSync } from './liveSync';\nimport { pull } from './pull';\nimport { push } from './push/push';\nimport { pushConfig } from './pushConfig';\nimport { reviewDoc } from './reviewDoc';\nimport { testMissingTranslations } from './test';\nimport { transform } from './transform';\nimport { translateDoc } from './translateDoc';\nimport { getParentPackageJSON } from './utils/getParentPackageJSON';\nimport { watchContentDeclaration } from './watch';\n\n// Extended AI options to include customPrompt\ntype AIOptions = BaseAIOptions & {\n customPrompt?: string;\n};\n\nconst isESModule = typeof import.meta.url === 'string';\n\nexport const dirname = isESModule\n ? pathDirname(fileURLToPath(import.meta.url))\n : __dirname;\n\nconst packageJson = getParentPackageJSON(dirname);\n\nconst logOptions = [\n ['--verbose', 'Verbose (default to true using CLI)'],\n ['--prefix [prefix]', 'Prefix'],\n];\n\nconst configurationOptions = [\n ['--env-file [envFile]', 'Environment file'],\n ['-e, --env [env]', 'Environment'],\n ['--base-dir [baseDir]', 'Base directory'],\n ['--no-cache [noCache]', 'No cache'],\n ...logOptions,\n];\n\nconst aiOptions = [\n ['--provider [provider]', 'Provider'],\n ['--temperature [temperature]', 'Temperature'],\n ['--model [model]', 'Model'],\n ['--api-key [apiKey]', 'Provider API key'],\n ['--custom-prompt [prompt]', 'Custom prompt'],\n ['--application-context [applicationContext]', 'Application context'],\n];\n\nconst gitOptions = [\n ['--git-diff [gitDiff]', 'Git diff mode - Check git diff between two refs'],\n ['--git-diff-base [gitDiffBase]', 'Git diff base ref'],\n ['--git-diff-current [gitDiffCurrent]', 'Git diff current ref'],\n ['--uncommitted [uncommitted]', 'Uncommitted'],\n ['--unpushed [unpushed]', 'Unpushed'],\n ['--untracked [untracked]', 'Untracked'],\n];\n\nconst extractKeysFromOptions = (options: object, keys: string[]) =>\n keys.filter((key) => options[key as keyof typeof options]);\n\n/**\n * Helper functions to apply common options to commands\n */\nconst applyOptions = (command: Command, options: string[][]) => {\n options.forEach(([flag, description]) => {\n command.option(flag, description);\n });\n return command;\n};\n\nconst removeUndefined = <T extends Record<string, any>>(obj: T): T =>\n Object.fromEntries(\n Object.entries(obj).filter(([_, value]) => value !== undefined)\n ) as T;\n\nconst applyConfigOptions = (command: Command) =>\n applyOptions(command, configurationOptions);\nconst applyAIOptions = (command: Command) => applyOptions(command, aiOptions);\nconst applyGitOptions = (command: Command) => applyOptions(command, gitOptions);\n\nconst extractAiOptions = (options: AIOptions): AIOptions | undefined => {\n const {\n apiKey,\n provider,\n model,\n temperature,\n applicationContext,\n customPrompt,\n } = options;\n\n const configuration = getConfiguration();\n const { ai } = configuration;\n\n return removeUndefined({\n ...ai,\n apiKey: apiKey ?? configuration.ai?.apiKey,\n provider: provider ?? (configuration.ai?.provider as AIOptions['provider']),\n model: model ?? configuration.ai?.model,\n temperature: temperature ?? configuration.ai?.temperature,\n applicationContext:\n applicationContext ?? configuration.ai?.applicationContext,\n customPrompt: customPrompt ?? (configuration.ai as any)?.customPrompt,\n });\n};\n\ntype GitOptions = {\n gitDiff?: boolean;\n gitDiffBase?: string;\n gitDiffCurrent?: string;\n uncommitted?: boolean;\n unpushed?: boolean;\n untracked?: boolean;\n};\n\nconst gitOptionKeys: (keyof GitOptions)[] = [\n 'gitDiff',\n 'gitDiffBase',\n 'gitDiffCurrent',\n 'uncommitted',\n 'unpushed',\n 'untracked',\n];\n\nconst extractGitOptions = (\n options: GitOptions\n): ListGitFilesOptions | undefined => {\n const filteredOptions = extractKeysFromOptions(options, gitOptionKeys);\n\n const isOptionEmpty = !Object.values(filteredOptions).some(Boolean);\n\n if (isOptionEmpty) return undefined;\n\n const {\n gitDiff,\n gitDiffBase,\n gitDiffCurrent,\n uncommitted,\n unpushed,\n untracked,\n } = options;\n\n const mode = [\n gitDiff && 'gitDiff',\n uncommitted && 'uncommitted',\n unpushed && 'unpushed',\n untracked && 'untracked',\n ].filter(Boolean) as DiffMode[];\n\n return removeUndefined({\n mode,\n baseRef: gitDiffBase,\n currentRef: gitDiffCurrent,\n absolute: true,\n });\n};\n\ntype LogOptions = {\n prefix?: string;\n verbose?: boolean;\n};\n\nexport type ConfigurationOptions = {\n baseDir?: string;\n env?: string;\n envFile?: string;\n noCache?: boolean;\n} & LogOptions;\n\nconst configurationOptionKeys: (keyof ConfigurationOptions)[] = [\n 'baseDir',\n 'env',\n 'envFile',\n 'verbose',\n 'prefix',\n];\n\nconst extractConfigOptions = (\n options: ConfigurationOptions\n): GetConfigurationOptions | undefined => {\n const configuration = getConfiguration(options);\n const filteredOptions = extractKeysFromOptions(\n options,\n configurationOptionKeys\n );\n\n const isOptionEmpty = !Object.values(filteredOptions).some(Boolean);\n\n if (isOptionEmpty) {\n return undefined;\n }\n\n const { baseDir, env, envFile, verbose, prefix, noCache } = options;\n\n const addPrefix: boolean = Boolean((options as any).with); // Hack to add the prefix when the command is run in parallel\n const log = {\n prefix: (prefix ?? addPrefix) ? configuration.log.prefix : '', // Should not consider the prefix set in the intlayer configuration file\n verbose: verbose ?? true,\n };\n\n const override = {\n log,\n };\n\n return removeUndefined({\n baseDir,\n env,\n envFile,\n override,\n cache: !noCache,\n });\n};\n\n/**\n * Set the API for the CLI\n *\n * Example of commands:\n *\n * npm run intlayer build --watch\n * npm run intlayer push --dictionaries id1 id2 id3 --deleteLocaleDir\n */\nexport const setAPI = (): Command => {\n const program = new Command();\n\n program.version(packageJson.version!).description('Intlayer CLI');\n\n // Explicit version subcommand for convenience: `npx intlayer version`\n program\n .command('version')\n .description('Print the Intlayer CLI version')\n .action(() => {\n // Prefer the resolved package.json version; fallback to unknown\n // Keeping output minimal to align with common CLI behavior\n console.log(packageJson.version ?? 'unknown');\n });\n\n /**\n * AUTH\n */\n const loginCmd = program\n .command('login')\n .description('Login to Intlayer')\n .option('--cms-url [cmsUrl]', 'CMS URL');\n\n applyConfigOptions(loginCmd);\n\n loginCmd.action((options) => {\n const configOptions = extractConfigOptions(options) ?? {\n override: {\n log: {\n prefix: '',\n verbose: true,\n },\n },\n };\n\n return login({\n cmsUrl: options.cmsUrl,\n configOptions,\n });\n });\n\n /**\n * INIT\n */\n program\n .command('init')\n .description('Initialize Intlayer in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .action((options) => init(options.projectRoot));\n\n /**\n * DICTIONARIES\n */\n\n const dictionariesProgram = program\n .command('dictionary')\n .alias('dictionaries')\n .alias('dic')\n .description('Dictionaries operations');\n\n // Dictionary build command\n const buildOptions = {\n description: 'Build the dictionaries',\n options: [\n ['-w, --watch', 'Watch for changes'],\n ['--skip-prepare', 'Skip the prepare step'],\n ['--with [with...]', 'Start command in parallel with the build'],\n ],\n };\n\n // Add build command to dictionaries program\n const dictionariesBuildCmd = dictionariesProgram\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(dictionariesBuildCmd, buildOptions.options);\n applyConfigOptions(dictionariesBuildCmd);\n dictionariesBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootBuildCmd = program\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(rootBuildCmd, buildOptions.options);\n applyConfigOptions(rootBuildCmd);\n rootBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const watchOptions = {\n description: 'Watch the dictionaries changes',\n options: [['--with [with...]', 'Start command in parallel with the build']],\n };\n\n // Add build command to dictionaries program\n const dictionariesWatchCmd = dictionariesProgram\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(dictionariesWatchCmd, watchOptions.options);\n applyConfigOptions(dictionariesWatchCmd);\n dictionariesWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootWatchCmd = program\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(rootWatchCmd, watchOptions.options);\n applyConfigOptions(rootWatchCmd);\n rootWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary pull command\n const pullOptions = {\n description: 'Pull dictionaries from the server',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to pull'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to pull (alias for --dictionaries)',\n ],\n ['--new-dictionaries-path [path]', 'Path to save the new dictionaries'],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--newDictionariesPath [path]',\n '[alias] Path to save the new dictionaries',\n ],\n ],\n };\n\n // Add pull command to dictionaries program\n const dictionariesPullCmd = dictionariesProgram\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(dictionariesPullCmd, pullOptions.options);\n applyConfigOptions(dictionariesPullCmd);\n dictionariesPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: {\n ...options.configOptions,\n baseDir: options.baseDir,\n },\n });\n });\n\n // Add pull command to root program as well\n const rootPullCmd = program\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(rootPullCmd, pullOptions.options);\n applyConfigOptions(rootPullCmd);\n rootPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary push command\n const pushOptions = {\n description:\n 'Push all dictionaries. Create or update the pushed dictionaries',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to push'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to push (alias for --dictionaries)',\n ],\n [\n '-r, --delete-locale-dictionary',\n 'Delete the local dictionaries after pushing',\n ],\n [\n '-k, --keep-locale-dictionary',\n 'Keep the local dictionaries after pushing',\n ],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--deleteLocaleDictionary',\n '[alias] Delete the local dictionaries after pushing',\n ],\n [\n '--keepLocaleDictionary',\n '[alias] Keep the local dictionaries after pushing',\n ],\n [\n '--build [build]',\n 'Build the dictionaries before pushing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build',\n ],\n ],\n };\n\n // Add push command to dictionaries program\n const dictionariesPushCmd = dictionariesProgram\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(dictionariesPushCmd, pushOptions.options);\n applyConfigOptions(dictionariesPushCmd);\n applyGitOptions(dictionariesPushCmd);\n\n dictionariesPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n // Add push command to root program as well\n const rootPushCmd = program\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(rootPushCmd, pushOptions.options);\n applyConfigOptions(rootPushCmd);\n applyGitOptions(rootPushCmd);\n\n rootPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * CONFIGURATION\n */\n\n // Define the parent command\n const configurationProgram = program\n .command('configuration')\n .alias('config')\n .alias('conf')\n .description('Configuration operations');\n\n const configGetCmd = configurationProgram\n .command('get')\n .description('Get the configuration');\n\n applyConfigOptions(configGetCmd);\n configGetCmd.action((options) => {\n getConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Define the `push config` subcommand and add it to the `push` command\n const configPushCmd = configurationProgram\n .command('push')\n .description('Push the configuration');\n\n applyConfigOptions(configPushCmd);\n configPushCmd.action((options) => {\n pushConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n /**\n * PROJECTS\n */\n\n const projectsProgram = program\n .command('projects')\n .alias('project')\n .description('List Intlayer projects');\n\n const projectsListCmd = projectsProgram\n .command('list')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--json', 'Output the results as JSON');\n\n projectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n });\n });\n\n // Add alias for projects list command at root level\n const rootProjectsListCmd = program\n .command('projects-list')\n .alias('pl')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--absolute', 'Output the results as absolute paths')\n .option('--json', 'Output the results as JSON');\n\n rootProjectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n /**\n * CONTENT DECLARATION\n */\n\n const contentProgram = program\n .command('content')\n .description('Content declaration operations');\n\n contentProgram\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n // Add alias for content list command\n program\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n const testProgram = contentProgram\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(testProgram);\n testProgram.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add alias for content test command\n const rootTestCmd = program\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(rootTestCmd);\n rootTestCmd.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const fillProgram = program\n .command('fill')\n .description('Fill the dictionaries')\n .option('-f, --file [files...]', 'List of Dictionary files to fill')\n .option('--source-locale [sourceLocale]', 'Source locale to translate from')\n .option(\n '--output-locales [outputLocales...]',\n 'Target locales to translate to'\n )\n .option(\n '--mode [mode]',\n 'Fill mode: complete, review. Complete will fill all missing content, review will fill missing content and review existing keys',\n 'complete'\n )\n .option('-k, --keys [keys...]', 'Filter dictionaries based on keys')\n .option(\n '--key [keys...]',\n 'Filter dictionaries based on keys (alias for --keys)'\n )\n .option(\n '--excluded-keys [excludedKeys...]',\n 'Filter out dictionaries based on keys'\n )\n .option(\n '--excluded-key [excludedKeys...]',\n 'Filter out dictionaries based on keys (alias for --excluded-keys)'\n )\n .option(\n '--path-filter [pathFilters...]',\n 'Filter dictionaries based on glob pattern'\n )\n .option(\n '--build [build]',\n 'Build the dictionaries before filling to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n )\n .option(\n '--skip-metadata',\n 'Skip filling missing metadata (description, title, tags) for dictionaries'\n );\n\n applyConfigOptions(fillProgram);\n applyAIOptions(fillProgram);\n applyGitOptions(fillProgram);\n\n fillProgram.action((options) => {\n // Merge key aliases\n const keys = [...(options.keys ?? []), ...(options.key ?? [])];\n const excludedKeys = [\n ...(options.excludedKeys ?? []),\n ...(options.excludedKey ?? []),\n ];\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n return fill({\n ...options,\n keys: keys.length > 0 ? keys : undefined,\n excludedKeys: excludedKeys.length > 0 ? excludedKeys : undefined,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * DOCS\n */\n\n const docParams = [\n ['--doc-pattern [docPattern...]', 'Documentation pattern'],\n [\n '--excluded-glob-pattern [excludedGlobPattern...]',\n 'Excluded glob pattern',\n ],\n [\n '--nb-simultaneous-file-processed [nbSimultaneousFileProcessed]',\n 'Number of simultaneous file processed',\n ],\n ['--locales [locales...]', 'Locales'],\n ['--base-locale [baseLocale]', 'Base locale'],\n [\n '--custom-instructions [customInstructions]',\n 'Custom instructions added to the prompt. Usefull to apply specific rules regarding formatting, urls translation, etc.',\n ],\n [\n '--skip-if-modified-before [skipIfModifiedBefore]',\n 'Skip the file if it has been modified before the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n [\n '--skip-if-modified-after [skipIfModifiedAfter]',\n 'Skip the file if it has been modified within the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n ['--skip-if-exists', 'Skip the file if it already exists'],\n ];\n\n const docProgram = program\n .command('doc')\n .description('Documentation operations');\n\n const translateProgram = docProgram\n .command('translate')\n .description('Translate the documentation');\n\n applyConfigOptions(translateProgram);\n applyAIOptions(translateProgram);\n applyGitOptions(translateProgram);\n applyOptions(translateProgram, docParams);\n\n translateProgram.action((options) =>\n translateDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n const reviewProgram = docProgram\n .command('review')\n .description('Review the documentation');\n\n applyConfigOptions(reviewProgram);\n applyAIOptions(reviewProgram);\n applyGitOptions(reviewProgram);\n applyOptions(reviewProgram, docParams);\n\n reviewProgram.action((options) =>\n reviewDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n /**\n * LIVE SYNC\n */\n\n const liveOptions = [\n ['--with [with...]', 'Start command in parallel with the live sync'],\n ];\n\n const liveCmd = program\n .command('live')\n .description(\n 'Live sync - Watch for changes made on the CMS and update the application content accordingly'\n );\n\n applyOptions(liveCmd, liveOptions);\n applyConfigOptions(liveCmd);\n\n liveCmd.action((options) => liveSync(options));\n\n /**\n * EDITOR\n */\n\n const editorProgram = program\n .command('editor')\n .description('Visual editor operations');\n\n const editorStartCmd = editorProgram\n .command('start')\n .description('Start the Intlayer visual editor');\n\n applyConfigOptions(editorStartCmd);\n\n editorStartCmd.action((options) => {\n startEditor({\n env: options.env,\n envFile: options.envFile,\n });\n });\n\n /**\n * TRANSFORM\n */\n const transformProgram = program\n .command('transform')\n .alias('trans')\n .description('Transform components to use Intlayer');\n\n transformProgram\n .option('-f, --file [files...]', 'List of files to transform')\n .option(\n '-o, --output-content-declarations [outputContentDeclarations]',\n 'Path to output content declaration files'\n )\n .option('--code-only', 'Only transform the component code', false)\n .option('--declaration-only', 'Only generate content declaration', false)\n .action((options) => {\n transform({\n files: options.file,\n outputContentDeclarations: options.outputContentDeclarations,\n configOptions: extractConfigOptions(options),\n codeOnly: options.codeOnly,\n declarationOnly: options.declarationOnly,\n });\n });\n\n applyConfigOptions(transformProgram);\n\n program.parse(process.argv);\n\n /**\n * CI / AUTOMATION\n *\n * Used to iterate over all projects in a monorepo, and help to parse secrets\n */\n program\n .command('ci')\n .description(\n 'Run Intlayer commands with auto-injected credentials from INTLAYER_PROJECT_CREDENTIALS. Detects current project or iterates over all projects.'\n )\n .argument(\n '<command...>',\n 'The intlayer command to execute (e.g., \"fill\", \"push\")'\n )\n .allowUnknownOption() // Allows passing flags like --verbose to the subcommand\n .action((args) => {\n runCI(args);\n });\n\n return program;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["isESModule","pathDirname","gitOptionKeys: (keyof GitOptions)[]","configurationOptionKeys: (keyof ConfigurationOptions)[]","addPrefix: boolean"],"sources":["../../src/cli.ts"],"sourcesContent":["import { dirname as pathDirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AIOptions as BaseAIOptions } from '@intlayer/api';\nimport type { DiffMode, ListGitFilesOptions } from '@intlayer/chokidar';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config';\nimport { Command } from 'commander';\nimport { login } from './auth/login';\nimport { build } from './build';\nimport { runCI } from './ci';\nimport { getConfig } from './config';\nimport { startEditor } from './editor';\nimport { type FillOptions, fill } from './fill/fill';\nimport { init } from './init';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { listProjectsCommand } from './listProjects';\nimport { liveSync } from './liveSync';\nimport { pull } from './pull';\nimport { push } from './push/push';\nimport { pushConfig } from './pushConfig';\nimport { reviewDoc } from './reviewDoc/reviewDoc';\nimport { testMissingTranslations } from './test';\nimport { transform } from './transform';\nimport { translateDoc } from './translateDoc/translateDoc';\nimport { getParentPackageJSON } from './utils/getParentPackageJSON';\nimport { watchContentDeclaration } from './watch';\n\n// Extended AI options to include customPrompt\ntype AIOptions = BaseAIOptions & {\n customPrompt?: string;\n};\n\nconst isESModule = typeof import.meta.url === 'string';\n\nexport const dirname = isESModule\n ? pathDirname(fileURLToPath(import.meta.url))\n : __dirname;\n\nconst packageJson = getParentPackageJSON(dirname);\n\nconst logOptions = [\n ['--verbose', 'Verbose (default to true using CLI)'],\n ['--prefix [prefix]', 'Prefix'],\n];\n\nconst configurationOptions = [\n ['--env-file [envFile]', 'Environment file'],\n ['-e, --env [env]', 'Environment'],\n ['--base-dir [baseDir]', 'Base directory'],\n ['--no-cache [noCache]', 'No cache'],\n ...logOptions,\n];\n\nconst aiOptions = [\n ['--provider [provider]', 'Provider'],\n ['--temperature [temperature]', 'Temperature'],\n ['--model [model]', 'Model'],\n ['--api-key [apiKey]', 'Provider API key'],\n ['--custom-prompt [prompt]', 'Custom prompt'],\n ['--application-context [applicationContext]', 'Application context'],\n];\n\nconst gitOptions = [\n ['--git-diff [gitDiff]', 'Git diff mode - Check git diff between two refs'],\n ['--git-diff-base [gitDiffBase]', 'Git diff base ref'],\n ['--git-diff-current [gitDiffCurrent]', 'Git diff current ref'],\n ['--uncommitted [uncommitted]', 'Uncommitted'],\n ['--unpushed [unpushed]', 'Unpushed'],\n ['--untracked [untracked]', 'Untracked'],\n];\n\nconst extractKeysFromOptions = (options: object, keys: string[]) =>\n keys.filter((key) => options[key as keyof typeof options]);\n\n/**\n * Helper functions to apply common options to commands\n */\nconst applyOptions = (command: Command, options: string[][]) => {\n options.forEach(([flag, description]) => {\n command.option(flag, description);\n });\n return command;\n};\n\nconst removeUndefined = <T extends Record<string, any>>(obj: T): T =>\n Object.fromEntries(\n Object.entries(obj).filter(([_, value]) => value !== undefined)\n ) as T;\n\nconst applyConfigOptions = (command: Command) =>\n applyOptions(command, configurationOptions);\nconst applyAIOptions = (command: Command) => applyOptions(command, aiOptions);\nconst applyGitOptions = (command: Command) => applyOptions(command, gitOptions);\n\nconst extractAiOptions = (options: AIOptions): AIOptions | undefined => {\n const {\n apiKey,\n provider,\n model,\n temperature,\n applicationContext,\n customPrompt,\n } = options;\n\n const configuration = getConfiguration();\n const { ai } = configuration;\n\n return removeUndefined({\n ...ai,\n apiKey: apiKey ?? configuration.ai?.apiKey,\n provider: provider ?? (configuration.ai?.provider as AIOptions['provider']),\n model: model ?? configuration.ai?.model,\n temperature: temperature ?? configuration.ai?.temperature,\n applicationContext:\n applicationContext ?? configuration.ai?.applicationContext,\n customPrompt: customPrompt ?? (configuration.ai as any)?.customPrompt,\n });\n};\n\ntype GitOptions = {\n gitDiff?: boolean;\n gitDiffBase?: string;\n gitDiffCurrent?: string;\n uncommitted?: boolean;\n unpushed?: boolean;\n untracked?: boolean;\n};\n\nconst gitOptionKeys: (keyof GitOptions)[] = [\n 'gitDiff',\n 'gitDiffBase',\n 'gitDiffCurrent',\n 'uncommitted',\n 'unpushed',\n 'untracked',\n];\n\nconst extractGitOptions = (\n options: GitOptions\n): ListGitFilesOptions | undefined => {\n const filteredOptions = extractKeysFromOptions(options, gitOptionKeys);\n\n const isOptionEmpty = !Object.values(filteredOptions).some(Boolean);\n\n if (isOptionEmpty) return undefined;\n\n const {\n gitDiff,\n gitDiffBase,\n gitDiffCurrent,\n uncommitted,\n unpushed,\n untracked,\n } = options;\n\n const mode = [\n gitDiff && 'gitDiff',\n uncommitted && 'uncommitted',\n unpushed && 'unpushed',\n untracked && 'untracked',\n ].filter(Boolean) as DiffMode[];\n\n return removeUndefined({\n mode,\n baseRef: gitDiffBase,\n currentRef: gitDiffCurrent,\n absolute: true,\n });\n};\n\ntype LogOptions = {\n prefix?: string;\n verbose?: boolean;\n};\n\nexport type ConfigurationOptions = {\n baseDir?: string;\n env?: string;\n envFile?: string;\n noCache?: boolean;\n} & LogOptions;\n\nconst configurationOptionKeys: (keyof ConfigurationOptions)[] = [\n 'baseDir',\n 'env',\n 'envFile',\n 'verbose',\n 'prefix',\n];\n\nconst extractConfigOptions = (\n options: ConfigurationOptions\n): GetConfigurationOptions | undefined => {\n const configuration = getConfiguration(options);\n const filteredOptions = extractKeysFromOptions(\n options,\n configurationOptionKeys\n );\n\n const isOptionEmpty = !Object.values(filteredOptions).some(Boolean);\n\n if (isOptionEmpty) {\n return undefined;\n }\n\n const { baseDir, env, envFile, verbose, prefix, noCache } = options;\n\n const addPrefix: boolean = Boolean((options as any).with); // Hack to add the prefix when the command is run in parallel\n const log = {\n prefix: (prefix ?? addPrefix) ? configuration.log.prefix : '', // Should not consider the prefix set in the intlayer configuration file\n verbose: verbose ?? true,\n };\n\n const override = {\n log,\n };\n\n return removeUndefined({\n baseDir,\n env,\n envFile,\n override,\n cache: !noCache,\n });\n};\n\n/**\n * Set the API for the CLI\n *\n * Example of commands:\n *\n * npm run intlayer build --watch\n * npm run intlayer push --dictionaries id1 id2 id3 --deleteLocaleDir\n */\nexport const setAPI = (): Command => {\n const program = new Command();\n\n program.version(packageJson.version!).description('Intlayer CLI');\n\n // Explicit version subcommand for convenience: `npx intlayer version`\n program\n .command('version')\n .description('Print the Intlayer CLI version')\n .action(() => {\n // Prefer the resolved package.json version; fallback to unknown\n // Keeping output minimal to align with common CLI behavior\n console.log(packageJson.version ?? 'unknown');\n });\n\n /**\n * AUTH\n */\n const loginCmd = program\n .command('login')\n .description('Login to Intlayer')\n .option('--cms-url [cmsUrl]', 'CMS URL');\n\n applyConfigOptions(loginCmd);\n\n loginCmd.action((options) => {\n const configOptions = extractConfigOptions(options) ?? {\n override: {\n log: {\n prefix: '',\n verbose: true,\n },\n },\n };\n\n return login({\n cmsUrl: options.cmsUrl,\n configOptions,\n });\n });\n\n /**\n * INIT\n */\n program\n .command('init')\n .description('Initialize Intlayer in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .action((options) => init(options.projectRoot));\n\n /**\n * DICTIONARIES\n */\n\n const dictionariesProgram = program\n .command('dictionary')\n .alias('dictionaries')\n .alias('dic')\n .description('Dictionaries operations');\n\n // Dictionary build command\n const buildOptions = {\n description: 'Build the dictionaries',\n options: [\n ['-w, --watch', 'Watch for changes'],\n ['--skip-prepare', 'Skip the prepare step'],\n ['--with [with...]', 'Start command in parallel with the build'],\n ],\n };\n\n // Add build command to dictionaries program\n const dictionariesBuildCmd = dictionariesProgram\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(dictionariesBuildCmd, buildOptions.options);\n applyConfigOptions(dictionariesBuildCmd);\n dictionariesBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootBuildCmd = program\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(rootBuildCmd, buildOptions.options);\n applyConfigOptions(rootBuildCmd);\n rootBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const watchOptions = {\n description: 'Watch the dictionaries changes',\n options: [['--with [with...]', 'Start command in parallel with the build']],\n };\n\n // Add build command to dictionaries program\n const dictionariesWatchCmd = dictionariesProgram\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(dictionariesWatchCmd, watchOptions.options);\n applyConfigOptions(dictionariesWatchCmd);\n dictionariesWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootWatchCmd = program\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(rootWatchCmd, watchOptions.options);\n applyConfigOptions(rootWatchCmd);\n rootWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary pull command\n const pullOptions = {\n description: 'Pull dictionaries from the server',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to pull'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to pull (alias for --dictionaries)',\n ],\n ['--new-dictionaries-path [path]', 'Path to save the new dictionaries'],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--newDictionariesPath [path]',\n '[alias] Path to save the new dictionaries',\n ],\n ],\n };\n\n // Add pull command to dictionaries program\n const dictionariesPullCmd = dictionariesProgram\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(dictionariesPullCmd, pullOptions.options);\n applyConfigOptions(dictionariesPullCmd);\n dictionariesPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: {\n ...options.configOptions,\n baseDir: options.baseDir,\n },\n });\n });\n\n // Add pull command to root program as well\n const rootPullCmd = program\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(rootPullCmd, pullOptions.options);\n applyConfigOptions(rootPullCmd);\n rootPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary push command\n const pushOptions = {\n description:\n 'Push all dictionaries. Create or update the pushed dictionaries',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to push'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to push (alias for --dictionaries)',\n ],\n [\n '-r, --delete-locale-dictionary',\n 'Delete the local dictionaries after pushing',\n ],\n [\n '-k, --keep-locale-dictionary',\n 'Keep the local dictionaries after pushing',\n ],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--deleteLocaleDictionary',\n '[alias] Delete the local dictionaries after pushing',\n ],\n [\n '--keepLocaleDictionary',\n '[alias] Keep the local dictionaries after pushing',\n ],\n [\n '--build [build]',\n 'Build the dictionaries before pushing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build',\n ],\n ],\n };\n\n // Add push command to dictionaries program\n const dictionariesPushCmd = dictionariesProgram\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(dictionariesPushCmd, pushOptions.options);\n applyConfigOptions(dictionariesPushCmd);\n applyGitOptions(dictionariesPushCmd);\n\n dictionariesPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n // Add push command to root program as well\n const rootPushCmd = program\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(rootPushCmd, pushOptions.options);\n applyConfigOptions(rootPushCmd);\n applyGitOptions(rootPushCmd);\n\n rootPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * CONFIGURATION\n */\n\n // Define the parent command\n const configurationProgram = program\n .command('configuration')\n .alias('config')\n .alias('conf')\n .description('Configuration operations');\n\n const configGetCmd = configurationProgram\n .command('get')\n .description('Get the configuration');\n\n applyConfigOptions(configGetCmd);\n configGetCmd.action((options) => {\n getConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Define the `push config` subcommand and add it to the `push` command\n const configPushCmd = configurationProgram\n .command('push')\n .description('Push the configuration');\n\n applyConfigOptions(configPushCmd);\n configPushCmd.action((options) => {\n pushConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n /**\n * PROJECTS\n */\n\n const projectsProgram = program\n .command('projects')\n .alias('project')\n .description('List Intlayer projects');\n\n const projectsListCmd = projectsProgram\n .command('list')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--json', 'Output the results as JSON');\n\n projectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n });\n });\n\n // Add alias for projects list command at root level\n const rootProjectsListCmd = program\n .command('projects-list')\n .alias('pl')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--absolute', 'Output the results as absolute paths')\n .option('--json', 'Output the results as JSON');\n\n rootProjectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n /**\n * CONTENT DECLARATION\n */\n\n const contentProgram = program\n .command('content')\n .description('Content declaration operations');\n\n contentProgram\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n // Add alias for content list command\n program\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n const testProgram = contentProgram\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(testProgram);\n testProgram.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add alias for content test command\n const rootTestCmd = program\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(rootTestCmd);\n rootTestCmd.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const fillProgram = program\n .command('fill')\n .description('Fill the dictionaries')\n .option('-f, --file [files...]', 'List of Dictionary files to fill')\n .option('--source-locale [sourceLocale]', 'Source locale to translate from')\n .option(\n '--output-locales [outputLocales...]',\n 'Target locales to translate to'\n )\n .option(\n '--mode [mode]',\n 'Fill mode: complete, review. Complete will fill all missing content, review will fill missing content and review existing keys',\n 'complete'\n )\n .option('-k, --keys [keys...]', 'Filter dictionaries based on keys')\n .option(\n '--key [keys...]',\n 'Filter dictionaries based on keys (alias for --keys)'\n )\n .option(\n '--excluded-keys [excludedKeys...]',\n 'Filter out dictionaries based on keys'\n )\n .option(\n '--excluded-key [excludedKeys...]',\n 'Filter out dictionaries based on keys (alias for --excluded-keys)'\n )\n .option(\n '--path-filter [pathFilters...]',\n 'Filter dictionaries based on glob pattern'\n )\n .option(\n '--build [build]',\n 'Build the dictionaries before filling to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n )\n .option(\n '--skip-metadata',\n 'Skip filling missing metadata (description, title, tags) for dictionaries'\n );\n\n applyConfigOptions(fillProgram);\n applyAIOptions(fillProgram);\n applyGitOptions(fillProgram);\n\n fillProgram.action((options) => {\n // Merge key aliases\n const keys = [...(options.keys ?? []), ...(options.key ?? [])];\n const excludedKeys = [\n ...(options.excludedKeys ?? []),\n ...(options.excludedKey ?? []),\n ];\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n return fill({\n ...options,\n keys: keys.length > 0 ? keys : undefined,\n excludedKeys: excludedKeys.length > 0 ? excludedKeys : undefined,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * DOCS\n */\n\n const docParams = [\n ['--doc-pattern [docPattern...]', 'Documentation pattern'],\n [\n '--excluded-glob-pattern [excludedGlobPattern...]',\n 'Excluded glob pattern',\n ],\n [\n '--nb-simultaneous-file-processed [nbSimultaneousFileProcessed]',\n 'Number of simultaneous file processed',\n ],\n ['--locales [locales...]', 'Locales'],\n ['--base-locale [baseLocale]', 'Base locale'],\n [\n '--custom-instructions [customInstructions]',\n 'Custom instructions added to the prompt. Usefull to apply specific rules regarding formatting, urls translation, etc.',\n ],\n [\n '--skip-if-modified-before [skipIfModifiedBefore]',\n 'Skip the file if it has been modified before the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n [\n '--skip-if-modified-after [skipIfModifiedAfter]',\n 'Skip the file if it has been modified within the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n ['--skip-if-exists', 'Skip the file if it already exists'],\n ];\n\n const docProgram = program\n .command('doc')\n .description('Documentation operations');\n\n const translateProgram = docProgram\n .command('translate')\n .description('Translate the documentation');\n\n applyConfigOptions(translateProgram);\n applyAIOptions(translateProgram);\n applyGitOptions(translateProgram);\n applyOptions(translateProgram, docParams);\n\n translateProgram.action((options) =>\n translateDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n const reviewProgram = docProgram\n .command('review')\n .description('Review the documentation');\n\n applyConfigOptions(reviewProgram);\n applyAIOptions(reviewProgram);\n applyGitOptions(reviewProgram);\n applyOptions(reviewProgram, docParams);\n\n reviewProgram.action((options) =>\n reviewDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n /**\n * LIVE SYNC\n */\n\n const liveOptions = [\n ['--with [with...]', 'Start command in parallel with the live sync'],\n ];\n\n const liveCmd = program\n .command('live')\n .description(\n 'Live sync - Watch for changes made on the CMS and update the application content accordingly'\n );\n\n applyOptions(liveCmd, liveOptions);\n applyConfigOptions(liveCmd);\n\n liveCmd.action((options) => liveSync(options));\n\n /**\n * EDITOR\n */\n\n const editorProgram = program\n .command('editor')\n .description('Visual editor operations');\n\n const editorStartCmd = editorProgram\n .command('start')\n .description('Start the Intlayer visual editor');\n\n applyConfigOptions(editorStartCmd);\n\n editorStartCmd.action((options) => {\n startEditor({\n env: options.env,\n envFile: options.envFile,\n });\n });\n\n /**\n * TRANSFORM\n */\n const transformProgram = program\n .command('transform')\n .alias('trans')\n .description('Transform components to use Intlayer');\n\n transformProgram\n .option('-f, --file [files...]', 'List of files to transform')\n .option(\n '-o, --output-content-declarations [outputContentDeclarations]',\n 'Path to output content declaration files'\n )\n .option('--code-only', 'Only transform the component code', false)\n .option('--declaration-only', 'Only generate content declaration', false)\n .action((options) => {\n transform({\n files: options.file,\n outputContentDeclarations: options.outputContentDeclarations,\n configOptions: extractConfigOptions(options),\n codeOnly: options.codeOnly,\n declarationOnly: options.declarationOnly,\n });\n });\n\n applyConfigOptions(transformProgram);\n\n program.parse(process.argv);\n\n /**\n * CI / AUTOMATION\n *\n * Used to iterate over all projects in a monorepo, and help to parse secrets\n */\n program\n .command('ci')\n .description(\n 'Run Intlayer commands with auto-injected credentials from INTLAYER_PROJECT_CREDENTIALS. Detects current project or iterates over all projects.'\n )\n .argument(\n '<command...>',\n 'The intlayer command to execute (e.g., \"fill\", \"push\")'\n )\n .allowUnknownOption() // Allows passing flags like --verbose to the subcommand\n .action((args) => {\n runCI(args);\n });\n\n return program;\n};\n"],"mappings":"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"}
@@ -8,9 +8,9 @@ import { liveSync } from "./liveSync.mjs";
8
8
  import { pull } from "./pull.mjs";
9
9
  import { push } from "./push/push.mjs";
10
10
  import { pushConfig } from "./pushConfig.mjs";
11
- import { reviewDoc } from "./reviewDoc.mjs";
11
+ import { reviewDoc } from "./reviewDoc/reviewDoc.mjs";
12
12
  import { transform } from "./transform.mjs";
13
- import { translateDoc, translateFile } from "./translateDoc.mjs";
13
+ import { translateDoc } from "./translateDoc/translateDoc.mjs";
14
14
  import { dirname, setAPI } from "./cli.mjs";
15
15
 
16
- export { build, dirname, fill, listContentDeclaration, listContentDeclarationRows, listMissingTranslations, listMissingTranslationsWithConfig, liveSync, pull, push, pushConfig, reviewDoc, setAPI, startEditor, testMissingTranslations, transform, translateDoc, translateFile };
16
+ export { build, dirname, fill, listContentDeclaration, listContentDeclarationRows, listMissingTranslations, listMissingTranslationsWithConfig, liveSync, pull, push, pushConfig, reviewDoc, setAPI, startEditor, testMissingTranslations, transform, translateDoc };
@@ -1,14 +1,14 @@
1
- import { setupAI } from "./utils/setupAI.mjs";
1
+ import { setupAI } from "../utils/setupAI.mjs";
2
+ import { checkFileModifiedRange } from "../utils/checkFileModifiedRange.mjs";
3
+ import { getOutputFilePath } from "../utils/getOutputFilePath.mjs";
2
4
  import { reviewFileBlockAware } from "./reviewDocBlockAware.mjs";
3
- import { checkFileModifiedRange } from "./utils/checkFileModifiedRange.mjs";
4
- import { getOutputFilePath } from "./utils/getOutputFilePath.mjs";
5
5
  import { formatLocale, formatPath, listGitFiles, listGitLines, parallelize } from "@intlayer/chokidar";
6
6
  import { ANSIColors, colorize, colorizeNumber, getAppLogger, getConfiguration } from "@intlayer/config";
7
7
  import { join, relative } from "node:path";
8
8
  import { existsSync } from "node:fs";
9
9
  import fg from "fast-glob";
10
10
 
11
- //#region src/reviewDoc.ts
11
+ //#region src/reviewDoc/reviewDoc.ts
12
12
  /**
13
13
  * Main audit function: scans all .md files in "en/" (unless you specified DOC_LIST),
14
14
  * then audits them to each locale in LOCALE_LIST.
@@ -41,14 +41,16 @@ const reviewDoc = async ({ docPattern, locales, excludedGlobPattern, baseLocale,
41
41
  appLogger(`${colorize("⊘", ANSIColors.YELLOW)} File ${formatPath(relativePath)} already exists, skipping.`);
42
42
  return;
43
43
  }
44
- const fileModificationData = checkFileModifiedRange(outputFilePath, {
45
- skipIfModifiedBefore,
46
- skipIfModifiedAfter
47
- });
48
- if (fileModificationData.isSkipped) {
49
- appLogger(fileModificationData.message);
50
- return;
51
- }
44
+ if (existsSync(outputFilePath)) {
45
+ const fileModificationData = checkFileModifiedRange(outputFilePath, {
46
+ skipIfModifiedBefore,
47
+ skipIfModifiedAfter
48
+ });
49
+ if (fileModificationData.isSkipped) {
50
+ appLogger(fileModificationData.message);
51
+ return;
52
+ }
53
+ } else if (skipIfModifiedBefore || skipIfModifiedAfter) appLogger(`${colorize("!", ANSIColors.YELLOW)} File ${formatPath(outputFilePath)} does not exist, skipping modification date check.`);
52
54
  let changedLines;
53
55
  if (gitOptions) {
54
56
  const gitChangedLines = await listGitLines(absoluteBaseFilePath, gitOptions);