@intlayer/cli 5.5.11 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/cli.cjs +5 -3
  3. package/dist/cjs/cli.cjs.map +1 -1
  4. package/dist/cjs/fill.cjs +2 -1
  5. package/dist/cjs/fill.cjs.map +1 -1
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/pull.cjs +1 -1
  8. package/dist/cjs/pull.cjs.map +1 -1
  9. package/dist/cjs/push.cjs +2 -1
  10. package/dist/cjs/push.cjs.map +1 -1
  11. package/dist/cjs/pushConfig.cjs +1 -1
  12. package/dist/cjs/pushConfig.cjs.map +1 -1
  13. package/dist/cjs/reviewDoc.cjs +34 -8
  14. package/dist/cjs/reviewDoc.cjs.map +1 -1
  15. package/dist/cjs/translateDoc.cjs +16 -6
  16. package/dist/cjs/translateDoc.cjs.map +1 -1
  17. package/dist/cjs/utils/chunkInference.cjs +1 -1
  18. package/dist/cjs/utils/chunkInference.cjs.map +1 -1
  19. package/dist/esm/cli.mjs +5 -3
  20. package/dist/esm/cli.mjs.map +1 -1
  21. package/dist/esm/fill.mjs +3 -2
  22. package/dist/esm/fill.mjs.map +1 -1
  23. package/dist/esm/index.mjs.map +1 -1
  24. package/dist/esm/pull.mjs +1 -1
  25. package/dist/esm/pull.mjs.map +1 -1
  26. package/dist/esm/push.mjs +3 -2
  27. package/dist/esm/push.mjs.map +1 -1
  28. package/dist/esm/pushConfig.mjs +1 -1
  29. package/dist/esm/pushConfig.mjs.map +1 -1
  30. package/dist/esm/reviewDoc.mjs +34 -8
  31. package/dist/esm/reviewDoc.mjs.map +1 -1
  32. package/dist/esm/translateDoc.mjs +16 -6
  33. package/dist/esm/translateDoc.mjs.map +1 -1
  34. package/dist/esm/utils/chunkInference.mjs +1 -1
  35. package/dist/esm/utils/chunkInference.mjs.map +1 -1
  36. package/dist/types/cli.d.ts.map +1 -1
  37. package/dist/types/fill.d.ts.map +1 -1
  38. package/dist/types/index.d.ts +1 -0
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/push.d.ts.map +1 -1
  41. package/dist/types/reviewDoc.d.ts +4 -2
  42. package/dist/types/reviewDoc.d.ts.map +1 -1
  43. package/dist/types/translateDoc.d.ts +3 -1
  44. package/dist/types/translateDoc.d.ts.map +1 -1
  45. package/dist/types/utils/chunkInference.d.ts.map +1 -1
  46. package/package.json +13 -13
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/reviewDoc.ts"],"sourcesContent":["import { AIOptions, getAuthAPI } from '@intlayer/api'; // Importing only getAiAPI for now\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n Locales,\n retryManager,\n} from '@intlayer/config';\nimport { getLocaleName } from '@intlayer/core';\nimport fg from 'fast-glob';\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { readFile } from 'fs/promises';\nimport pLimit from 'p-limit';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { chunkText } from './utils/calculateChunks';\nimport { checkAIAccess } from './utils/checkAIAccess';\nimport { checkFileModifiedRange } from './utils/checkFileModifiedRange';\nimport { chunkInference } from './utils/chunkInference';\nimport { fixChunkStartEndChars } from './utils/fixChunkStartEndChars';\nimport { getChunk } from './utils/getChunk';\nimport { getOutputFilePath } from './utils/getOutputFilePath';\n\nconst isESModule = typeof import.meta.url === 'string';\n\nconst dir = isESModule ? dirname(fileURLToPath(import.meta.url)) : __dirname;\n\n/**\n * Translate a single file for a given locale\n */\nexport const reviewFile = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locales,\n baseLocale: Locales,\n aiOptions?: AIOptions,\n configOptions?: GetConfigurationOptions,\n oAuth2AccessToken?: string,\n customInstructions?: string\n) => {\n try {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n const basedFileContent = await readFile(baseFilePath, 'utf-8');\n const fileToReviewContent = await readFile(outputFilePath, 'utf-8');\n\n let updatedFileContent = fileToReviewContent;\n let fileResultContent = '';\n\n // Prepare the base prompt for ChatGPT\n const basePrompt = (\n await readFile(join(dir, './prompts/REVIEW_PROMPT.md'), 'utf-8')\n )\n .replaceAll(\n '{{localeName}}',\n `${getLocaleName(locale, Locales.ENGLISH)} (${locale})`\n )\n .replaceAll(\n '{{baseLocaleName}}',\n `${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale})`\n )\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const baseChunks = chunkText(basedFileContent, 800, 0);\n\n appLogger(` Base file splitted into ${baseChunks.length} chunks`);\n\n for (let i = 0; i < baseChunks.length; i++) {\n const baseChunkContext = baseChunks[i];\n\n const getBaseChunkContextPrompt = () =>\n `**CHUNK ${i + 1} to ${Math.min(i + 3, baseChunks.length)} of ${baseChunks.length}** is the base chunk in ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale}) as reference.\\n` +\n `///chunksStart///` +\n (baseChunks[i - 1]?.content ?? '') +\n baseChunkContext.content +\n (baseChunks[i + 1]?.content ?? '') +\n `///chunksEnd///`;\n\n const getChunkToReviewPrompt = () =>\n `**CHUNK ${i + 1} to ${Math.min(i + 3, baseChunks.length)} of ${baseChunks.length}** is the current chunk to review in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}) as reference.\\n` +\n `///chunksStart///` +\n getChunk(updatedFileContent, {\n lineStart: baseChunks[i - 1]?.lineStart ?? 0,\n lineLength:\n (baseChunks[i - 1]?.lineLength ?? 0) +\n baseChunkContext.lineLength +\n (baseChunks[i + 1]?.lineLength ?? 0),\n }) +\n `///chunksEnd///`;\n\n // Make the actual translation call\n let reviewedChunkResult = await retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n { role: 'system', content: getBaseChunkContextPrompt() },\n { role: 'system', content: getChunkToReviewPrompt() },\n {\n role: 'system',\n content: `The next user message will be the **CHUNK ${i + 1} of ${baseChunks.length}** that should be translated in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}).`,\n },\n { role: 'user', content: baseChunkContext.content },\n ],\n aiOptions,\n oAuth2AccessToken\n );\n\n appLogger(\n ` -> ${result.tokenUsed} tokens used - CHUNK ${i + 1} of ${baseChunks.length}`\n );\n\n const fixedReviewedChunkResult = fixChunkStartEndChars(\n result?.fileContent,\n baseChunkContext.content\n );\n\n return fixedReviewedChunkResult;\n })();\n\n updatedFileContent = updatedFileContent.replace(\n baseChunkContext.content,\n reviewedChunkResult\n );\n\n fileResultContent += reviewedChunkResult;\n }\n\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, fileResultContent);\n\n appLogger(` File ${outputFilePath} created/updated successfully.`);\n } catch (error) {\n console.error(error);\n }\n};\n\ntype ReviewDocOptions = {\n docPattern: string[];\n locales: Locales[];\n excludedGlobPattern: string[];\n baseLocale: Locales;\n aiOptions?: AIOptions;\n nbSimultaneousFileProcessed?: number;\n configOptions?: GetConfigurationOptions;\n customInstructions?: string;\n skipIfModifiedBefore?: number | string | Date;\n skipIfModifiedAfter?: number | string | Date;\n};\n\n/**\n * Main audit function: scans all .md files in \"en/\" (unless you specified DOC_LIST),\n * then audits them to each locale in LOCALE_LIST.\n */\nexport const reviewDoc = async ({\n docPattern,\n locales,\n excludedGlobPattern,\n baseLocale,\n aiOptions,\n nbSimultaneousFileProcessed,\n configOptions,\n customInstructions,\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n}: ReviewDocOptions) => {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {\n appLogger(\n `Warning: nbSimultaneousFileProcessed is set to ${nbSimultaneousFileProcessed}, which is greater than 10. Setting it to 10.`\n );\n nbSimultaneousFileProcessed = 10; // Limit the number of simultaneous file processed to 10\n }\n\n const limit = pLimit(nbSimultaneousFileProcessed ?? 3);\n\n const docList: string[] = fg.sync(docPattern, {\n ignore: excludedGlobPattern,\n });\n\n checkAIAccess(configuration, aiOptions);\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getAuthAPI(undefined, configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger(\n `Base locale is ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale})`\n );\n appLogger(\n `Reviewing ${locales.length} locales: [ ${locales\n .map((locale) => `${getLocaleName(locale, Locales.ENGLISH)} (${locale})`)\n .join(', ')} ]`\n );\n\n appLogger(`Reviewing ${docList.length} files:`);\n appLogger(docList.map((path) => ` - ${path}\\n`));\n\n const tasks = docList.map((docPath) =>\n locales.flatMap((locale) =>\n limit(async () => {\n appLogger(\n `Reviewing file: ${docPath} to ${getLocaleName(\n locale,\n Locales.ENGLISH\n )} (${locale})`\n );\n\n const absoluteBaseFilePath = join(\n configuration.content.baseDir,\n docPath\n );\n const outputFilePath = getOutputFilePath(\n absoluteBaseFilePath,\n locale,\n baseLocale\n );\n\n const fileModificationData = checkFileModifiedRange(outputFilePath, {\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n });\n\n if (fileModificationData.isSkipped) {\n appLogger(fileModificationData.message);\n return;\n }\n\n await reviewFile(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locales,\n baseLocale,\n aiOptions,\n configOptions,\n oAuth2AccessToken,\n customInstructions\n );\n })\n )\n );\n\n await Promise.all(tasks);\n};\n"],"mappings":"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","names":["pLimit","fg"]}
1
+ {"version":3,"sources":["../../src/reviewDoc.ts"],"sourcesContent":["import { AIOptions } from '@intlayer/api'; // Importing only getAiAPI for now\nimport { listGitFiles, ListGitFilesOptions } from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n Locales,\n retryManager,\n} from '@intlayer/config';\nimport { getLocaleName } from '@intlayer/core';\nimport fg from 'fast-glob';\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { readFile } from 'fs/promises';\nimport pLimit from 'p-limit';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { getOAuthAPI } from '../../api/dist/types/getIntlayerAPI/oAuth';\nimport { chunkText } from './utils/calculateChunks';\nimport { checkAIAccess } from './utils/checkAIAccess';\nimport { checkFileModifiedRange } from './utils/checkFileModifiedRange';\nimport { chunkInference } from './utils/chunkInference';\nimport { fixChunkStartEndChars } from './utils/fixChunkStartEndChars';\nimport { getChunk } from './utils/getChunk';\nimport { getOutputFilePath } from './utils/getOutputFilePath';\n\nconst isESModule = typeof import.meta.url === 'string';\n\nconst dir = isESModule ? dirname(fileURLToPath(import.meta.url)) : __dirname;\n\n/**\n * Translate a single file for a given locale\n */\nexport const reviewFile = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locales,\n baseLocale: Locales,\n aiOptions?: AIOptions,\n configOptions?: GetConfigurationOptions,\n oAuth2AccessToken?: string,\n customInstructions?: string,\n changedLines?: number[]\n) => {\n try {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n const basedFileContent = await readFile(baseFilePath, 'utf-8');\n const fileToReviewContent = await readFile(outputFilePath, 'utf-8');\n\n let updatedFileContent = fileToReviewContent;\n let fileResultContent = '';\n\n // Prepare the base prompt for ChatGPT\n const basePrompt = (\n await readFile(join(dir, './prompts/REVIEW_PROMPT.md'), 'utf-8')\n )\n .replaceAll(\n '{{localeName}}',\n `${getLocaleName(locale, Locales.ENGLISH)} (${locale})`\n )\n .replaceAll(\n '{{baseLocaleName}}',\n `${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale})`\n )\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const baseChunks = chunkText(basedFileContent, 800, 0);\n\n appLogger(` Base file splitted into ${baseChunks.length} chunks`);\n\n for await (const [i, baseChunk] of baseChunks.entries()) {\n const baseChunkContext = baseChunk;\n\n if (changedLines) {\n const hasChangedLinesInChunk = changedLines.some(\n (line) =>\n line > baseChunkContext.lineStart &&\n line < baseChunkContext.lineStart + baseChunkContext.lineLength\n );\n\n if (!hasChangedLinesInChunk) {\n appLogger(`No git changed lines found for chunk ${i + 1}`);\n\n const chunkWithNoChange = getChunk(updatedFileContent, {\n lineStart: baseChunkContext.lineStart,\n lineLength: baseChunkContext.lineLength,\n });\n\n fileResultContent += chunkWithNoChange;\n\n continue;\n }\n }\n\n const getBaseChunkContextPrompt = () =>\n `**CHUNK ${i + 1} to ${Math.min(i + 3, baseChunks.length)} of ${baseChunks.length}** is the base chunk in ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale}) as reference.\\n` +\n `///chunksStart///` +\n (baseChunks[i - 1]?.content ?? '') +\n baseChunkContext.content +\n (baseChunks[i + 1]?.content ?? '') +\n `///chunksEnd///`;\n\n const getChunkToReviewPrompt = () =>\n `**CHUNK ${i + 1} to ${Math.min(i + 3, baseChunks.length)} of ${baseChunks.length}** is the current chunk to review in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}) as reference.\\n` +\n `///chunksStart///` +\n getChunk(updatedFileContent, {\n lineStart: baseChunks[i - 1]?.lineStart ?? 0,\n lineLength:\n (baseChunks[i - 1]?.lineLength ?? 0) +\n baseChunkContext.lineLength +\n (baseChunks[i + 1]?.lineLength ?? 0),\n }) +\n `///chunksEnd///`;\n\n // Make the actual translation call\n let reviewedChunkResult = await retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n { role: 'system', content: getBaseChunkContextPrompt() },\n { role: 'system', content: getChunkToReviewPrompt() },\n {\n role: 'system',\n content: `The next user message will be the **CHUNK ${i + 1} of ${baseChunks.length}** that should be translated in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}).`,\n },\n { role: 'user', content: baseChunkContext.content },\n ],\n aiOptions,\n oAuth2AccessToken\n );\n\n appLogger(\n ` -> ${result.tokenUsed} tokens used - CHUNK ${i + 1} of ${baseChunks.length}`\n );\n\n const fixedReviewedChunkResult = fixChunkStartEndChars(\n result?.fileContent,\n baseChunkContext.content\n );\n\n return fixedReviewedChunkResult;\n })();\n\n updatedFileContent = updatedFileContent.replace(\n baseChunkContext.content,\n reviewedChunkResult\n );\n\n fileResultContent += reviewedChunkResult;\n }\n\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, fileResultContent);\n\n appLogger(` File ${outputFilePath} created/updated successfully.`);\n } catch (error) {\n console.error(error);\n }\n};\n\ntype ReviewDocOptions = {\n docPattern: string[];\n locales: Locales[];\n excludedGlobPattern: string[];\n baseLocale: Locales;\n aiOptions?: AIOptions;\n nbSimultaneousFileProcessed?: number;\n configOptions?: GetConfigurationOptions;\n customInstructions?: string;\n skipIfModifiedBefore?: number | string | Date;\n skipIfModifiedAfter?: number | string | Date;\n gitOptions?: ListGitFilesOptions;\n};\n\n/**\n * Main audit function: scans all .md files in \"en/\" (unless you specified DOC_LIST),\n * then audits them to each locale in LOCALE_LIST.\n */\nexport const reviewDoc = async ({\n docPattern,\n locales,\n excludedGlobPattern,\n baseLocale,\n aiOptions,\n nbSimultaneousFileProcessed,\n configOptions,\n customInstructions,\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n gitOptions,\n}: ReviewDocOptions) => {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {\n appLogger(\n `Warning: nbSimultaneousFileProcessed is set to ${nbSimultaneousFileProcessed}, which is greater than 10. Setting it to 10.`\n );\n nbSimultaneousFileProcessed = 10; // Limit the number of simultaneous file processed to 10\n }\n\n const limit = pLimit(nbSimultaneousFileProcessed ?? 3);\n\n let docList: string[] = fg.sync(docPattern, {\n ignore: excludedGlobPattern,\n });\n\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n docList = docList.filter((path) =>\n gitChangedFiles.some((gitFile) => join(process.cwd(), path) === gitFile)\n );\n }\n }\n\n checkAIAccess(configuration, aiOptions);\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getOAuthAPI(configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger(\n `Base locale is ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale})`\n );\n appLogger(\n `Reviewing ${locales.length} locales: [ ${locales\n .map((locale) => `${getLocaleName(locale, Locales.ENGLISH)} (${locale})`)\n .join(', ')} ]`\n );\n\n appLogger(`Reviewing ${docList.length} files:`);\n appLogger(docList.map((path) => ` - ${path}\\n`));\n\n const tasks = docList.map((docPath) =>\n locales.flatMap((locale) =>\n limit(async () => {\n appLogger(\n `Reviewing file: ${docPath} to ${getLocaleName(\n locale,\n Locales.ENGLISH\n )} (${locale})`\n );\n\n const absoluteBaseFilePath = join(\n configuration.content.baseDir,\n docPath\n );\n const outputFilePath = getOutputFilePath(\n absoluteBaseFilePath,\n locale,\n baseLocale\n );\n\n const fileModificationData = checkFileModifiedRange(outputFilePath, {\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n });\n\n if (fileModificationData.isSkipped) {\n appLogger(fileModificationData.message);\n return;\n }\n\n let changedLines: number[] | undefined = undefined;\n // Disabled for now because it's leading to file format issues\n // if (gitOptions) {\n // const gitChangedLines = await listGitLines(\n // absoluteBaseFilePath,\n // gitOptions\n // );\n\n // appLogger(`Git changed lines: ${gitChangedLines.join(', ')}`);\n\n // changedLines = gitChangedLines;\n // }\n\n await reviewFile(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locales,\n baseLocale,\n aiOptions,\n configOptions,\n oAuth2AccessToken,\n customInstructions,\n changedLines\n );\n })\n )\n );\n\n await Promise.all(tasks);\n};\n"],"mappings":"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","names":["pLimit","fg"]}
@@ -32,7 +32,7 @@ __export(translateDoc_exports, {
32
32
  translateFile: () => translateFile
33
33
  });
34
34
  module.exports = __toCommonJS(translateDoc_exports);
35
- var import_api = require("@intlayer/api");
35
+ var import_chokidar = require("@intlayer/chokidar");
36
36
  var import_config = require("@intlayer/config");
37
37
  var import_core = require("@intlayer/core");
38
38
  var import_fast_glob = __toESM(require("fast-glob"));
@@ -41,6 +41,7 @@ var import_promises = require("fs/promises");
41
41
  var import_p_limit = __toESM(require("p-limit"));
42
42
  var import_path = require("path");
43
43
  var import_url = require("url");
44
+ var import_oAuth = require('../../api/dist/types/getIntlayerAPI/oAuth.cjs');
44
45
  var import_calculateChunks = require('./utils/calculateChunks.cjs');
45
46
  var import_checkAIAccess = require('./utils/checkAIAccess.cjs');
46
47
  var import_checkFileModifiedRange = require('./utils/checkFileModifiedRange.cjs');
@@ -66,13 +67,13 @@ const translateFile = async (baseFilePath, outputFilePath, locale, baseLocale, a
66
67
  ).replace("{{applicationContext}}", aiOptions?.applicationContext ?? "-").replace("{{customInstructions}}", customInstructions ?? "-");
67
68
  const chunks = (0, import_calculateChunks.chunkText)(fileContent);
68
69
  appLogger(`Base file splitted into ${chunks.length} chunks`);
69
- for (let i = 0; i < chunks.length; i++) {
70
+ for await (const [i, chunk] of chunks.entries()) {
70
71
  const isFirstChunk = i === 0;
71
72
  const getPrevChunkPrompt = () => `**CHUNK ${i} of ${chunks.length}** that has been translated in ${(0, import_core.getLocaleName)(locale, import_config.Locales.ENGLISH)} (${locale}):
72
73
  ///chunkStart///` + (0, import_getChunk.getChunk)(fileResultContent, chunks[i - 1]) + `///chunkEnd///`;
73
74
  const getBaseChunkContextPrompt = () => `**CHUNK ${i + 1} to ${Math.min(i + 3, chunks.length)} of ${chunks.length}** is the base chunk in ${(0, import_core.getLocaleName)(baseLocale, import_config.Locales.ENGLISH)} (${baseLocale}) as reference.
74
75
  ///chunksStart///` + (chunks[i - 1]?.content ?? "") + chunks[i].content + (chunks[i + 1]?.content ?? "") + `///chunksEnd///`;
75
- const fileToTranslateCurrentChunk = chunks[i].content;
76
+ const fileToTranslateCurrentChunk = chunk.content;
76
77
  let chunkTranslation = await (0, import_config.retryManager)(async () => {
77
78
  const result = await (0, import_chunkInference.chunkInference)(
78
79
  [
@@ -119,7 +120,8 @@ const translateDoc = async ({
119
120
  configOptions,
120
121
  customInstructions,
121
122
  skipIfModifiedBefore,
122
- skipIfModifiedAfter
123
+ skipIfModifiedAfter,
124
+ gitOptions
123
125
  }) => {
124
126
  const configuration = (0, import_config.getConfiguration)(configOptions);
125
127
  const appLogger = (0, import_config.getAppLogger)(configuration);
@@ -130,13 +132,21 @@ const translateDoc = async ({
130
132
  nbSimultaneousFileProcessed = 10;
131
133
  }
132
134
  const limit = (0, import_p_limit.default)(nbSimultaneousFileProcessed ?? 3);
133
- const docList = import_fast_glob.default.sync(docPattern, {
135
+ let docList = import_fast_glob.default.sync(docPattern, {
134
136
  ignore: excludedGlobPattern
135
137
  });
136
138
  (0, import_checkAIAccess.checkAIAccess)(configuration, aiOptions);
139
+ if (gitOptions) {
140
+ const gitChangedFiles = await (0, import_chokidar.listGitFiles)(gitOptions);
141
+ if (gitChangedFiles) {
142
+ docList = docList.filter(
143
+ (path) => gitChangedFiles.some((gitFile) => (0, import_path.join)(process.cwd(), path) === gitFile)
144
+ );
145
+ }
146
+ }
137
147
  let oAuth2AccessToken;
138
148
  if (configuration.editor.clientId) {
139
- const intlayerAuthAPI = (0, import_api.getAuthAPI)(void 0, configuration);
149
+ const intlayerAuthAPI = (0, import_oAuth.getOAuthAPI)(configuration);
140
150
  const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();
141
151
  oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
142
152
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/translateDoc.ts"],"sourcesContent":["import { AIOptions, getAuthAPI } from '@intlayer/api';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n Locales,\n retryManager,\n} from '@intlayer/config';\nimport { getLocaleName } from '@intlayer/core';\nimport fg from 'fast-glob';\nimport { existsSync, mkdirSync, writeFileSync } from 'fs';\nimport { readFile } from 'fs/promises';\nimport pLimit from 'p-limit';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { chunkText } from './utils/calculateChunks';\nimport { checkAIAccess } from './utils/checkAIAccess';\nimport { checkFileModifiedRange } from './utils/checkFileModifiedRange';\nimport { chunkInference } from './utils/chunkInference';\nimport { fixChunkStartEndChars } from './utils/fixChunkStartEndChars';\nimport { getChunk } from './utils/getChunk';\nimport { getOutputFilePath } from './utils/getOutputFilePath';\n\nconst isESModule = typeof import.meta.url === 'string';\n\nconst dir = isESModule ? dirname(fileURLToPath(import.meta.url)) : __dirname;\n\n/**\n * Translate a single file for a given locale\n */\nexport const translateFile = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locales,\n baseLocale: Locales,\n aiOptions?: AIOptions,\n configOptions?: GetConfigurationOptions,\n oAuth2AccessToken?: string,\n customInstructions?: string\n) => {\n try {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n // Determine the target locale file path\n const fileContent = await readFile(baseFilePath, 'utf-8');\n let fileResultContent = fileContent;\n\n // Prepare the base prompt for ChatGPT\n const basePrompt = (\n await readFile(join(dir, './prompts/TRANSLATE_PROMPT.md'), 'utf-8')\n )\n .replaceAll(\n '{{localeName}}',\n `${getLocaleName(locale, Locales.ENGLISH)} (${locale})`\n )\n .replaceAll(\n '{{baseLocaleName}}',\n `${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale})`\n )\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n // 1. Chunk the file by number of lines instead of characters\n const chunks = chunkText(fileContent);\n appLogger(`Base file splitted into ${chunks.length} chunks`);\n\n for (let i = 0; i < chunks.length; i++) {\n const isFirstChunk = i === 0;\n\n // Build the chunk-specific prompt\n const getPrevChunkPrompt = () =>\n `**CHUNK ${i} of ${chunks.length}** that has been translated in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}):\\n` +\n `///chunkStart///` +\n getChunk(fileResultContent, chunks[i - 1]) +\n `///chunkEnd///`;\n\n const getBaseChunkContextPrompt = () =>\n `**CHUNK ${i + 1} to ${Math.min(i + 3, chunks.length)} of ${chunks.length}** is the base chunk in ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale}) as reference.\\n` +\n `///chunksStart///` +\n (chunks[i - 1]?.content ?? '') +\n chunks[i].content +\n (chunks[i + 1]?.content ?? '') +\n `///chunksEnd///`;\n\n const fileToTranslateCurrentChunk = chunks[i].content;\n\n // Make the actual translation call\n let chunkTranslation = await retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n\n { role: 'system', content: getBaseChunkContextPrompt() },\n ...(isFirstChunk\n ? []\n : [{ role: 'system', content: getPrevChunkPrompt() } as const]),\n {\n role: 'system',\n content: `The next user message will be the **CHUNK ${i + 1} of ${chunks.length}** in ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale}) to translate in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}):`,\n },\n { role: 'user', content: fileToTranslateCurrentChunk },\n ],\n aiOptions,\n oAuth2AccessToken\n );\n\n appLogger(\n ` -> ${result.tokenUsed} tokens used - CHUNK ${i + 1} of ${chunks.length}`\n );\n\n const fixedTranslatedChunkResult = fixChunkStartEndChars(\n result?.fileContent,\n fileToTranslateCurrentChunk\n );\n\n return fixedTranslatedChunkResult;\n })();\n\n // Replace the chunk in the file content\n fileResultContent = fileResultContent.replace(\n fileToTranslateCurrentChunk,\n chunkTranslation\n );\n }\n\n // 4. Write the final translation to the appropriate file path\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, fileResultContent);\n\n appLogger(`File ${outputFilePath} created/updated successfully.`);\n } catch (error) {\n console.error(error);\n }\n};\n\ntype TranslateDocOptions = {\n docPattern: string[];\n locales: Locales[];\n excludedGlobPattern: string[];\n baseLocale: Locales;\n aiOptions?: AIOptions;\n nbSimultaneousFileProcessed?: number;\n configOptions?: GetConfigurationOptions;\n customInstructions?: string;\n skipIfModifiedBefore?: number | string | Date;\n skipIfModifiedAfter?: number | string | Date;\n};\n\n/**\n * Main translate function: scans all .md files in \"en/\" (unless you specified DOC_LIST),\n * then translates them to each locale in LOCALE_LIST.\n */\nexport const translateDoc = async ({\n docPattern,\n locales,\n excludedGlobPattern,\n baseLocale,\n aiOptions,\n nbSimultaneousFileProcessed,\n configOptions,\n customInstructions,\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n}: TranslateDocOptions) => {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {\n appLogger(\n `Warning: nbSimultaneousFileProcessed is set to ${nbSimultaneousFileProcessed}, which is greater than 10. Setting it to 10.`\n );\n nbSimultaneousFileProcessed = 10; // Limit the number of simultaneous file processed to 10\n }\n\n const limit = pLimit(nbSimultaneousFileProcessed ?? 3);\n\n const docList: string[] = fg.sync(docPattern, {\n ignore: excludedGlobPattern,\n });\n\n checkAIAccess(configuration, aiOptions);\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getAuthAPI(undefined, configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger(`Base locale is ${getLocaleName(baseLocale)} (${baseLocale})`);\n appLogger(\n `Translating ${locales.length} locales: [ ${locales\n .map((locale) => `${getLocaleName(locale, baseLocale)} (${locale})`)\n .join(', ')} ]`\n );\n\n appLogger(`Translating ${docList.length} files:`);\n appLogger(docList.map((path) => ` - ${path}\\n`));\n\n const tasks = docList.map((docPath) =>\n locales.flatMap((locale) =>\n limit(async () => {\n appLogger(\n `Translating file: ${docPath} to ${getLocaleName(\n locale,\n Locales.ENGLISH\n )} (${locale})`\n );\n\n const absoluteBaseFilePath = join(\n configuration.content.baseDir,\n docPath\n );\n const outputFilePath = getOutputFilePath(\n absoluteBaseFilePath,\n locale,\n baseLocale\n );\n\n // check if the file exist, otherwise create it\n if (!existsSync(outputFilePath)) {\n appLogger(`File ${outputFilePath} does not exist, creating it...`);\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, '');\n }\n\n const fileModificationData = checkFileModifiedRange(outputFilePath, {\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n });\n\n if (fileModificationData.isSkipped) {\n appLogger(fileModificationData.message);\n return;\n }\n\n await translateFile(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locales,\n baseLocale,\n aiOptions,\n configOptions,\n oAuth2AccessToken,\n customInstructions\n );\n })\n )\n );\n\n await Promise.all(tasks);\n};\n"],"mappings":"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","names":["pLimit","fg"]}
1
+ {"version":3,"sources":["../../src/translateDoc.ts"],"sourcesContent":["import { AIOptions } from '@intlayer/api';\nimport { listGitFiles, ListGitFilesOptions } from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n Locales,\n retryManager,\n} from '@intlayer/config';\nimport { getLocaleName } from '@intlayer/core';\nimport fg from 'fast-glob';\nimport { existsSync, mkdirSync, writeFileSync } from 'fs';\nimport { readFile } from 'fs/promises';\nimport pLimit from 'p-limit';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { getOAuthAPI } from '../../api/dist/types/getIntlayerAPI/oAuth';\nimport { chunkText } from './utils/calculateChunks';\nimport { checkAIAccess } from './utils/checkAIAccess';\nimport { checkFileModifiedRange } from './utils/checkFileModifiedRange';\nimport { chunkInference } from './utils/chunkInference';\nimport { fixChunkStartEndChars } from './utils/fixChunkStartEndChars';\nimport { getChunk } from './utils/getChunk';\nimport { getOutputFilePath } from './utils/getOutputFilePath';\n\nconst isESModule = typeof import.meta.url === 'string';\n\nconst dir = isESModule ? dirname(fileURLToPath(import.meta.url)) : __dirname;\n\n/**\n * Translate a single file for a given locale\n */\nexport const translateFile = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locales,\n baseLocale: Locales,\n aiOptions?: AIOptions,\n configOptions?: GetConfigurationOptions,\n oAuth2AccessToken?: string,\n customInstructions?: string\n) => {\n try {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n // Determine the target locale file path\n const fileContent = await readFile(baseFilePath, 'utf-8');\n let fileResultContent = fileContent;\n\n // Prepare the base prompt for ChatGPT\n const basePrompt = (\n await readFile(join(dir, './prompts/TRANSLATE_PROMPT.md'), 'utf-8')\n )\n .replaceAll(\n '{{localeName}}',\n `${getLocaleName(locale, Locales.ENGLISH)} (${locale})`\n )\n .replaceAll(\n '{{baseLocaleName}}',\n `${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale})`\n )\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n // 1. Chunk the file by number of lines instead of characters\n const chunks = chunkText(fileContent);\n appLogger(`Base file splitted into ${chunks.length} chunks`);\n\n for await (const [i, chunk] of chunks.entries()) {\n const isFirstChunk = i === 0;\n\n // Build the chunk-specific prompt\n const getPrevChunkPrompt = () =>\n `**CHUNK ${i} of ${chunks.length}** that has been translated in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}):\\n` +\n `///chunkStart///` +\n getChunk(fileResultContent, chunks[i - 1]) +\n `///chunkEnd///`;\n\n const getBaseChunkContextPrompt = () =>\n `**CHUNK ${i + 1} to ${Math.min(i + 3, chunks.length)} of ${chunks.length}** is the base chunk in ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale}) as reference.\\n` +\n `///chunksStart///` +\n (chunks[i - 1]?.content ?? '') +\n chunks[i].content +\n (chunks[i + 1]?.content ?? '') +\n `///chunksEnd///`;\n\n const fileToTranslateCurrentChunk = chunk.content;\n\n // Make the actual translation call\n let chunkTranslation = await retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n\n { role: 'system', content: getBaseChunkContextPrompt() },\n ...(isFirstChunk\n ? []\n : [{ role: 'system', content: getPrevChunkPrompt() } as const]),\n {\n role: 'system',\n content: `The next user message will be the **CHUNK ${i + 1} of ${chunks.length}** in ${getLocaleName(baseLocale, Locales.ENGLISH)} (${baseLocale}) to translate in ${getLocaleName(locale, Locales.ENGLISH)} (${locale}):`,\n },\n { role: 'user', content: fileToTranslateCurrentChunk },\n ],\n aiOptions,\n oAuth2AccessToken\n );\n\n appLogger(\n ` -> ${result.tokenUsed} tokens used - CHUNK ${i + 1} of ${chunks.length}`\n );\n\n const fixedTranslatedChunkResult = fixChunkStartEndChars(\n result?.fileContent,\n fileToTranslateCurrentChunk\n );\n\n return fixedTranslatedChunkResult;\n })();\n\n // Replace the chunk in the file content\n fileResultContent = fileResultContent.replace(\n fileToTranslateCurrentChunk,\n chunkTranslation\n );\n }\n\n // 4. Write the final translation to the appropriate file path\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, fileResultContent);\n\n appLogger(`File ${outputFilePath} created/updated successfully.`);\n } catch (error) {\n console.error(error);\n }\n};\n\ntype TranslateDocOptions = {\n docPattern: string[];\n locales: Locales[];\n excludedGlobPattern: string[];\n baseLocale: Locales;\n aiOptions?: AIOptions;\n nbSimultaneousFileProcessed?: number;\n configOptions?: GetConfigurationOptions;\n customInstructions?: string;\n skipIfModifiedBefore?: number | string | Date;\n skipIfModifiedAfter?: number | string | Date;\n gitOptions?: ListGitFilesOptions;\n};\n\n/**\n * Main translate function: scans all .md files in \"en/\" (unless you specified DOC_LIST),\n * then translates them to each locale in LOCALE_LIST.\n */\nexport const translateDoc = async ({\n docPattern,\n locales,\n excludedGlobPattern,\n baseLocale,\n aiOptions,\n nbSimultaneousFileProcessed,\n configOptions,\n customInstructions,\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n gitOptions,\n}: TranslateDocOptions) => {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger(configuration);\n\n if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {\n appLogger(\n `Warning: nbSimultaneousFileProcessed is set to ${nbSimultaneousFileProcessed}, which is greater than 10. Setting it to 10.`\n );\n nbSimultaneousFileProcessed = 10; // Limit the number of simultaneous file processed to 10\n }\n\n const limit = pLimit(nbSimultaneousFileProcessed ?? 3);\n\n let docList: string[] = fg.sync(docPattern, {\n ignore: excludedGlobPattern,\n });\n\n checkAIAccess(configuration, aiOptions);\n\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n docList = docList.filter((path) =>\n gitChangedFiles.some((gitFile) => join(process.cwd(), path) === gitFile)\n );\n }\n }\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getOAuthAPI(configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger(`Base locale is ${getLocaleName(baseLocale)} (${baseLocale})`);\n appLogger(\n `Translating ${locales.length} locales: [ ${locales\n .map((locale) => `${getLocaleName(locale, baseLocale)} (${locale})`)\n .join(', ')} ]`\n );\n\n appLogger(`Translating ${docList.length} files:`);\n appLogger(docList.map((path) => ` - ${path}\\n`));\n\n const tasks = docList.map((docPath) =>\n locales.flatMap((locale) =>\n limit(async () => {\n appLogger(\n `Translating file: ${docPath} to ${getLocaleName(\n locale,\n Locales.ENGLISH\n )} (${locale})`\n );\n\n const absoluteBaseFilePath = join(\n configuration.content.baseDir,\n docPath\n );\n const outputFilePath = getOutputFilePath(\n absoluteBaseFilePath,\n locale,\n baseLocale\n );\n\n // check if the file exist, otherwise create it\n if (!existsSync(outputFilePath)) {\n appLogger(`File ${outputFilePath} does not exist, creating it...`);\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, '');\n }\n\n const fileModificationData = checkFileModifiedRange(outputFilePath, {\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n });\n\n if (fileModificationData.isSkipped) {\n appLogger(fileModificationData.message);\n return;\n }\n\n await translateFile(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locales,\n baseLocale,\n aiOptions,\n configOptions,\n oAuth2AccessToken,\n customInstructions\n );\n })\n )\n );\n\n await Promise.all(tasks);\n};\n"],"mappings":"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","names":["pLimit","fg"]}
@@ -43,7 +43,7 @@ const chunkInference = async (messages, aiOptions, oAuth2AccessToken) => {
43
43
  throw new Error("No response from AI API");
44
44
  }
45
45
  const { fileContent, tokenUsed } = response.data;
46
- const newContent = fileContent.replaceAll("///chunksStart///", "").replaceAll("///chunkStart///", "").replaceAll("///chunksEnd///", "").replaceAll("///chunkEnd///", "");
46
+ const newContent = fileContent.replaceAll("///chunksStart///", "").replaceAll("///chunkStart///", "").replaceAll("///chunksEnd///", "").replaceAll("///chunkEnd///", "").replaceAll("///chunksStart///", "").replaceAll("chunkStart///", "").replaceAll("chunksEnd///", "").replaceAll("chunkEnd///", "").replaceAll("///chunksStart", "").replaceAll("///chunkStart", "").replaceAll("///chunksEnd", "").replaceAll("///chunkEnd", "").replaceAll("chunksStart", "").replaceAll("chunkStart", "").replaceAll("chunksEnd", "").replaceAll("chunkEnd", "");
47
47
  lastResult = {
48
48
  fileContent: newContent,
49
49
  tokenUsed
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/chunkInference.ts"],"sourcesContent":["import { type AIOptions, type Messages, getAiAPI } from '@intlayer/api';\nimport { retryManager } from '@intlayer/config';\n\ntype ChunkInferenceResult = {\n fileContent: string;\n tokenUsed: number;\n};\n\n/**\n * Translates a single chunk via the OpenAI API.\n * Includes retry logic if the call fails.\n */\nexport const chunkInference = async (\n messages: Messages,\n aiOptions?: AIOptions,\n oAuth2AccessToken?: string\n): Promise<ChunkInferenceResult> => {\n let lastResult: ChunkInferenceResult;\n\n await retryManager(async () => {\n const response = await getAiAPI().customQuery(\n {\n aiOptions,\n messages,\n },\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n if (!response.data) {\n throw new Error('No response from AI API');\n }\n\n const { fileContent, tokenUsed } = response.data;\n\n const newContent = fileContent\n .replaceAll('///chunksStart///', '')\n .replaceAll('///chunkStart///', '')\n .replaceAll('///chunksEnd///', '')\n .replaceAll('///chunkEnd///', '');\n\n lastResult = {\n fileContent: newContent,\n tokenUsed,\n };\n })();\n\n return lastResult!;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAwD;AACxD,oBAA6B;AAWtB,MAAM,iBAAiB,OAC5B,UACA,WACA,sBACkC;AAClC,MAAI;AAEJ,YAAM,4BAAa,YAAY;AAC7B,UAAM,WAAW,UAAM,qBAAS,EAAE;AAAA,MAChC;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,QACE,GAAI,qBAAqB;AAAA,UACvB,SAAS;AAAA,YACP,eAAe,UAAU,iBAAiB;AAAA,UAC5C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,EAAE,aAAa,UAAU,IAAI,SAAS;AAE5C,UAAM,aAAa,YAChB,WAAW,qBAAqB,EAAE,EAClC,WAAW,oBAAoB,EAAE,EACjC,WAAW,mBAAmB,EAAE,EAChC,WAAW,kBAAkB,EAAE;AAElC,iBAAa;AAAA,MACX,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF,CAAC,EAAE;AAEH,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/chunkInference.ts"],"sourcesContent":["import { type AIOptions, type Messages, getAiAPI } from '@intlayer/api';\nimport { retryManager } from '@intlayer/config';\n\ntype ChunkInferenceResult = {\n fileContent: string;\n tokenUsed: number;\n};\n\n/**\n * Translates a single chunk via the OpenAI API.\n * Includes retry logic if the call fails.\n */\nexport const chunkInference = async (\n messages: Messages,\n aiOptions?: AIOptions,\n oAuth2AccessToken?: string\n): Promise<ChunkInferenceResult> => {\n let lastResult: ChunkInferenceResult;\n\n await retryManager(async () => {\n const response = await getAiAPI().customQuery(\n {\n aiOptions,\n messages,\n },\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n if (!response.data) {\n throw new Error('No response from AI API');\n }\n\n const { fileContent, tokenUsed } = response.data;\n\n const newContent = fileContent\n .replaceAll('///chunksStart///', '')\n .replaceAll('///chunkStart///', '')\n .replaceAll('///chunksEnd///', '')\n .replaceAll('///chunkEnd///', '')\n .replaceAll('///chunksStart///', '')\n .replaceAll('chunkStart///', '')\n .replaceAll('chunksEnd///', '')\n .replaceAll('chunkEnd///', '')\n .replaceAll('///chunksStart', '')\n .replaceAll('///chunkStart', '')\n .replaceAll('///chunksEnd', '')\n .replaceAll('///chunkEnd', '')\n .replaceAll('chunksStart', '')\n .replaceAll('chunkStart', '')\n .replaceAll('chunksEnd', '')\n .replaceAll('chunkEnd', '');\n\n lastResult = {\n fileContent: newContent,\n tokenUsed,\n };\n })();\n\n return lastResult!;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAwD;AACxD,oBAA6B;AAWtB,MAAM,iBAAiB,OAC5B,UACA,WACA,sBACkC;AAClC,MAAI;AAEJ,YAAM,4BAAa,YAAY;AAC7B,UAAM,WAAW,UAAM,qBAAS,EAAE;AAAA,MAChC;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,QACE,GAAI,qBAAqB;AAAA,UACvB,SAAS;AAAA,YACP,eAAe,UAAU,iBAAiB;AAAA,UAC5C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,EAAE,aAAa,UAAU,IAAI,SAAS;AAE5C,UAAM,aAAa,YAChB,WAAW,qBAAqB,EAAE,EAClC,WAAW,oBAAoB,EAAE,EACjC,WAAW,mBAAmB,EAAE,EAChC,WAAW,kBAAkB,EAAE,EAC/B,WAAW,qBAAqB,EAAE,EAClC,WAAW,iBAAiB,EAAE,EAC9B,WAAW,gBAAgB,EAAE,EAC7B,WAAW,eAAe,EAAE,EAC5B,WAAW,kBAAkB,EAAE,EAC/B,WAAW,iBAAiB,EAAE,EAC9B,WAAW,gBAAgB,EAAE,EAC7B,WAAW,eAAe,EAAE,EAC5B,WAAW,eAAe,EAAE,EAC5B,WAAW,cAAc,EAAE,EAC3B,WAAW,aAAa,EAAE,EAC1B,WAAW,YAAY,EAAE;AAE5B,iBAAa;AAAA,MACX,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF,CAAC,EAAE;AAEH,SAAO;AACT;","names":[]}
package/dist/esm/cli.mjs CHANGED
@@ -165,7 +165,7 @@ const setAPI = () => {
165
165
  description: "Pull dictionaries from the server",
166
166
  options: [
167
167
  ["-d, --dictionaries [ids...]", "List of dictionary IDs to pull"],
168
- ["--newDictionariesPath [path]", "Path to save the new dictionaries"]
168
+ ["--new-dictionaries-path [path]", "Path to save the new dictionaries"]
169
169
  ]
170
170
  };
171
171
  const dictionariesPullCmd = dictionariesProgram.command("pull").description(pullOptions.description);
@@ -194,11 +194,11 @@ const setAPI = () => {
194
194
  options: [
195
195
  ["-d, --dictionaries [ids...]", "List of dictionary IDs to push"],
196
196
  [
197
- "-r, --deleteLocaleDictionary",
197
+ "-r, --delete-locale-dictionary",
198
198
  "Delete the local dictionaries after pushing"
199
199
  ],
200
200
  [
201
- "-k, --keepLocaleDictionary",
201
+ "-k, --keep-locale-dictionary",
202
202
  "Keep the local dictionaries after pushing"
203
203
  ]
204
204
  ]
@@ -306,6 +306,7 @@ const setAPI = () => {
306
306
  locales: options.locales,
307
307
  baseLocale: options.baseLocale,
308
308
  aiOptions: extractAiOptions(options),
309
+ gitOptions: extractGitOptions(options),
309
310
  nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,
310
311
  configOptions: extractConfigOptions(options),
311
312
  customInstructions: options.customInstructions,
@@ -325,6 +326,7 @@ const setAPI = () => {
325
326
  locales: options.locales,
326
327
  baseLocale: options.baseLocale,
327
328
  aiOptions: extractAiOptions(options),
329
+ gitOptions: extractGitOptions(options),
328
330
  nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,
329
331
  configOptions: extractConfigOptions(options),
330
332
  customInstructions: options.customInstructions,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["import type { AIOptions as BaseAIOptions } from '@intlayer/api';\nimport { GetConfigurationOptions, isESModule } from '@intlayer/config';\nimport configuration from '@intlayer/config/built';\nimport { Command } from 'commander';\nimport { dirname as pathDirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport {\n DiffMode,\n ListGitFilesOptions,\n} from '../../chokidar/dist/types/listGitFiles';\nimport { build } from './build';\nimport { getConfig } from './config';\nimport { fill, FillOptions } from './fill';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { pull } from './pull';\nimport { push } from './push';\nimport { pushConfig } from './pushConfig';\nimport { reviewDoc } from './reviewDoc';\nimport { translateDoc } from './translateDoc';\nimport { getParentPackageJSON } from './utils/getParentPackageJSON';\n\n// Extended AI options to include customPrompt\ntype AIOptions = BaseAIOptions & {\n customPrompt?: string;\n};\n\nexport const dirname = isESModule\n ? pathDirname(fileURLToPath(import.meta.url))\n : __dirname;\n\nconst packageJson = getParentPackageJSON(dirname);\n\nconst logOptions = [\n ['--verbose', 'Verbose'],\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 ...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]) => command.option(flag, description));\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 return removeUndefined({\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} & 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 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 } = options;\n\n const log = {\n prefix: prefix ?? '', // Should not consider the prefix set in the intlayer configuration file\n verbose,\n };\n\n const override = {\n log,\n };\n\n return removeUndefined({\n baseDir,\n env,\n envFile,\n override,\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 /**\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: [['-w, --watch', 'Watch for changes']],\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 // 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 ['--newDictionariesPath [path]', 'Path to save the new dictionaries'],\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 pull({\n ...options,\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 pull({\n ...options,\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 '-r, --deleteLocaleDictionary',\n 'Delete the local dictionaries after pushing',\n ],\n [\n '-k, --keepLocaleDictionary',\n 'Keep the local dictionaries after pushing',\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 push({\n ...options,\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 push({\n ...options,\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 * CONTENT DECLARATION\n */\n\n program\n .command('content list')\n .description('List the content declaration files')\n .action(listContentDeclaration);\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 'review'\n )\n .option('-k, --keys [keys...]', 'Filter dictionaries based on keys')\n .option(\n '--excluded-keys [excludedKeys...]',\n 'Filter out dictionaries based on keys'\n )\n .option(\n '--path-filter [pathFilters...]',\n 'Filter dictionaries based on glob pattern'\n );\n\n applyConfigOptions(fillProgram);\n applyAIOptions(fillProgram);\n applyGitOptions(fillProgram);\n\n fillProgram.action((options) =>\n fill({\n ...options,\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 ];\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 nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\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 nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n })\n );\n\n program.parse(process.argv);\n\n return program;\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["import type { AIOptions as BaseAIOptions } from '@intlayer/api';\nimport { GetConfigurationOptions, isESModule } from '@intlayer/config';\nimport configuration from '@intlayer/config/built';\nimport { Command } from 'commander';\nimport { dirname as pathDirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport {\n DiffMode,\n ListGitFilesOptions,\n} from '../../chokidar/dist/types/listGitFiles';\nimport { build } from './build';\nimport { getConfig } from './config';\nimport { fill, FillOptions } from './fill';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { pull } from './pull';\nimport { push } from './push';\nimport { pushConfig } from './pushConfig';\nimport { reviewDoc } from './reviewDoc';\nimport { translateDoc } from './translateDoc';\nimport { getParentPackageJSON } from './utils/getParentPackageJSON';\n\n// Extended AI options to include customPrompt\ntype AIOptions = BaseAIOptions & {\n customPrompt?: string;\n};\n\nexport const dirname = isESModule\n ? pathDirname(fileURLToPath(import.meta.url))\n : __dirname;\n\nconst packageJson = getParentPackageJSON(dirname);\n\nconst logOptions = [\n ['--verbose', 'Verbose'],\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 ...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]) => command.option(flag, description));\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 return removeUndefined({\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} & 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 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 } = options;\n\n const log = {\n prefix: prefix ?? '', // Should not consider the prefix set in the intlayer configuration file\n verbose,\n };\n\n const override = {\n log,\n };\n\n return removeUndefined({\n baseDir,\n env,\n envFile,\n override,\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 /**\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: [['-w, --watch', 'Watch for changes']],\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 // 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 ['--new-dictionaries-path [path]', 'Path to save the new dictionaries'],\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 pull({\n ...options,\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 pull({\n ...options,\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 '-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 ],\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 push({\n ...options,\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 push({\n ...options,\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 * CONTENT DECLARATION\n */\n\n program\n .command('content list')\n .description('List the content declaration files')\n .action(listContentDeclaration);\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 'review'\n )\n .option('-k, --keys [keys...]', 'Filter dictionaries based on keys')\n .option(\n '--excluded-keys [excludedKeys...]',\n 'Filter out dictionaries based on keys'\n )\n .option(\n '--path-filter [pathFilters...]',\n 'Filter dictionaries based on glob pattern'\n );\n\n applyConfigOptions(fillProgram);\n applyAIOptions(fillProgram);\n applyGitOptions(fillProgram);\n\n fillProgram.action((options) =>\n fill({\n ...options,\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 ];\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 })\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 })\n );\n\n program.parse(process.argv);\n\n return program;\n};\n"],"mappings":"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","names":[]}
package/dist/esm/fill.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { getAiAPI, getAuthAPI } from "@intlayer/api";
1
+ import { getAiAPI } from "@intlayer/api";
2
2
  import {
3
3
  getFilteredLocalesContent,
4
4
  listGitFiles,
@@ -17,6 +17,7 @@ import {
17
17
  import dictionariesRecord from "@intlayer/dictionaries-entry";
18
18
  import unmergedDictionariesRecord from "@intlayer/unmerged-dictionaries-entry";
19
19
  import { dirname, extname, join } from "path";
20
+ import { getOAuthAPI } from "../../api/dist/types/getIntlayerAPI/oAuth.mjs";
20
21
  import { checkAIAccess } from "./utils/checkAIAccess.mjs";
21
22
  const ensureArray = (value) => [value].flat();
22
23
  const getTargetDictionary = async (options) => {
@@ -197,7 +198,7 @@ const fill = async (options) => {
197
198
  checkAIAccess(configuration, options.aiOptions);
198
199
  let oAuth2AccessToken;
199
200
  if (configuration.editor.clientId) {
200
- const intlayerAuthAPI = getAuthAPI(void 0, configuration);
201
+ const intlayerAuthAPI = getOAuthAPI(configuration);
201
202
  const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();
202
203
  oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
203
204
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fill.ts"],"sourcesContent":["import { AIOptions, getAiAPI, getAuthAPI } from '@intlayer/api'; // Importing only getAiAPI for now\nimport {\n getFilteredLocalesContent,\n listGitFiles,\n ListGitFilesOptions,\n mergeDictionaries,\n processPerLocaleDictionary,\n reduceDictionaryContent,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n type IntlayerConfig,\n Locales,\n} from '@intlayer/config';\nimport {\n type AutoFill,\n type ContentNode,\n type Dictionary,\n getLocalisedContent,\n} from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport unmergedDictionariesRecord from '@intlayer/unmerged-dictionaries-entry';\nimport { dirname, extname, join } from 'path';\nimport { checkAIAccess } from './utils/checkAIAccess';\n\n// Arguments for the fill function\nexport type FillOptions = {\n sourceLocale?: Locales;\n outputLocales?: Locales | Locales[];\n file?: string | string[];\n mode?: 'complete' | 'review';\n keys?: string | string[];\n excludedKeys?: string | string[];\n filter?: (entry: Dictionary) => boolean; // DictionaryEntry needs to be defined\n pathFilter?: string | string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n aiOptions?: AIOptions; // Added aiOptions to be passed to translateJSON\n verbose?: boolean;\n};\n\nconst ensureArray = <T>(value: T | T[]): T[] => [value].flat() as T[];\n\nconst getTargetDictionary = async (options: FillOptions) => {\n const configuration = getConfiguration(options.configOptions);\n\n const { baseDir } = configuration.content;\n\n let result = Object.values(unmergedDictionariesRecord).flat();\n\n // 1. if filePath not defined, list all content declaration files based on unmerged dictionaries list\n if (typeof options.file !== 'undefined') {\n const fileArray = ensureArray(options.file);\n const absoluteFilePaths = fileArray.map((file) => join(baseDir, file));\n\n result = result.filter(\n (dict) =>\n dict.filePath &&\n (absoluteFilePaths.includes(dict.filePath) ||\n absoluteFilePaths.includes(join(baseDir, dict.filePath)))\n );\n }\n\n if (typeof options.keys !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.keys)?.includes(dict.key)\n );\n }\n\n if (typeof options.excludedKeys !== 'undefined') {\n result = result.filter(\n (dict) => !ensureArray(options.excludedKeys)?.includes(dict.key)\n );\n }\n\n if (typeof options.pathFilter !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.pathFilter)?.includes(dict.filePath ?? '')\n );\n }\n\n if (typeof options.filter !== 'undefined') {\n result = result.filter(options.filter);\n }\n\n const gitOptions = options.gitOptions;\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n result = result.filter((dict) => {\n if (!dict.filePath) return false;\n\n return gitChangedFiles.some((gitFile) => dict.filePath === gitFile);\n });\n }\n }\n\n return result.filter((dict) => !dict.autoFilled);\n};\n\nconst transformUriToAbsolutePath = (\n uri: string,\n filePath: string,\n baseDir: string\n) => {\n if (uri.startsWith('/')) {\n return join(baseDir, uri);\n }\n\n if (uri.startsWith('./')) {\n return join(dirname(filePath), uri);\n }\n\n return filePath;\n};\n\nexport type AutoFillData = {\n localeList: Locales[];\n filePath: string;\n};\n\nconst formatAutoFillData = (\n autoFillOptions: AutoFill,\n localeList: Locales[],\n filePath: string,\n dictionaryKey: string,\n configuration: IntlayerConfig\n): AutoFillData[] => {\n const outputContentDeclarationFile: AutoFillData[] = [];\n\n if (!Boolean(autoFillOptions)) return outputContentDeclarationFile;\n\n if (autoFillOptions === true) {\n // wanted jsonFilePath: /..../src/components/home/index.content.json\n // replace file extension in json\n let jsonFilePath = filePath.replace(extname(filePath), '.json');\n\n // if both filePath jsonFilePath are same path, change it as : /..../src/components/home/index.fill.content.json\n if (filePath === jsonFilePath) {\n jsonFilePath = jsonFilePath.replace(extname(jsonFilePath), '.fill.json');\n }\n\n outputContentDeclarationFile.push({\n localeList,\n filePath: jsonFilePath,\n });\n }\n\n if (typeof autoFillOptions === 'string') {\n if (autoFillOptions.includes('{{locale}}')) {\n const output = localeList.map((locale) => ({\n localeList: [locale],\n filePath: transformUriToAbsolutePath(\n autoFillOptions\n .replace('{{locale}}', locale)\n .replace('{{key}}', dictionaryKey),\n filePath,\n configuration.content.baseDir\n ),\n }));\n\n outputContentDeclarationFile.push(...output);\n } else {\n outputContentDeclarationFile.push({\n localeList,\n filePath: transformUriToAbsolutePath(\n autoFillOptions,\n filePath,\n configuration.content.baseDir\n ),\n });\n }\n\n return outputContentDeclarationFile;\n }\n\n if (typeof autoFillOptions === 'object') {\n const localeList = Object.keys(autoFillOptions).filter(\n (locale) => typeof autoFillOptions[locale] === 'string'\n ) as Locales[];\n\n const output: AutoFillData[] = localeList.map((locale) => ({\n localeList: [locale],\n filePath: transformUriToAbsolutePath(\n autoFillOptions[locale].replace('{{key}}', dictionaryKey),\n filePath,\n configuration.content.baseDir\n ),\n }));\n\n // Group by filePath and merge localeList\n const groupedByFilePath = output.reduce((acc, curr) => {\n const existing = acc.find((item) => item.filePath === curr.filePath);\n if (existing) {\n existing.localeList.push(...curr.localeList);\n } else {\n acc.push(curr);\n }\n return acc;\n }, [] as AutoFillData[]);\n\n outputContentDeclarationFile.push(...groupedByFilePath);\n }\n\n return outputContentDeclarationFile;\n};\n\nconst autoFill = async (\n fullDictionary: Dictionary,\n contentDeclarationFile: Dictionary,\n autoFillOptions: AutoFill,\n outputLocales: Locales[],\n parentLocales: Locales[],\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n let localeList: Locales[] = (\n outputLocales ?? configuration.internationalization.locales\n ).filter((locale) => !parentLocales?.includes(locale));\n\n const filePath = contentDeclarationFile.filePath;\n\n if (!filePath) {\n appLogger('No file path found for dictionary', {\n level: 'error',\n });\n return;\n }\n\n const autoFillData: AutoFillData[] = formatAutoFillData(\n autoFillOptions,\n localeList,\n filePath,\n fullDictionary.key,\n configuration\n );\n\n appLogger(`Auto fill data: ${JSON.stringify(autoFillData, null, 2)}`, {\n level: 'info',\n isVerbose: true,\n });\n\n for await (const output of autoFillData) {\n const reducedDictionary = reduceDictionaryContent(\n fullDictionary,\n contentDeclarationFile\n );\n\n const isPerLocaleDeclarationFile = output.localeList.length === 1;\n\n if (isPerLocaleDeclarationFile) {\n const sourceLocale = output.localeList[0];\n\n const sourceLocaleContent = getLocalisedContent(\n reducedDictionary as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n await writeContentDeclaration({\n ...fullDictionary,\n locale: sourceLocale,\n autoFilled: true,\n autoFill: undefined,\n content: sourceLocaleContent.content,\n filePath: output.filePath,\n });\n } else {\n const content = getFilteredLocalesContent(\n reducedDictionary.content as unknown as ContentNode,\n output.localeList,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n // write file\n await writeContentDeclaration({\n ...fullDictionary,\n autoFilled: true,\n autoFill: undefined,\n content,\n filePath: output.filePath,\n });\n }\n }\n};\n\n/**\n * Fill translations based on the provided options.\n */\nexport const fill = async (options: FillOptions): Promise<void> => {\n const configuration = getConfiguration(options.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const { defaultLocale, locales } = configuration.internationalization;\n const mode = options.mode ?? 'review';\n const baseLocale = options.sourceLocale ?? defaultLocale;\n\n checkAIAccess(configuration, options.aiOptions);\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getAuthAPI(undefined, configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger('Starting fill function', {\n level: 'info',\n });\n\n const targetUnmergedDictionaries = await getTargetDictionary(options);\n\n // Determine output locales\n const outputLocalesList: Locales[] = (\n options.outputLocales ? ensureArray(options.outputLocales) : locales\n ).filter((locale) =>\n // If mode is review, translate all locales\n // If mode is complete, translate only the locales that are not the source locale\n mode === 'review' ? true : locale !== baseLocale\n );\n\n const affectedDictionaryKeys = new Set<string>();\n targetUnmergedDictionaries.forEach((dict) => {\n affectedDictionaryKeys.add(dict.key);\n });\n\n appLogger(\n [\n 'Affected dictionary keys for processing:',\n Array.from(affectedDictionaryKeys).join(', '),\n ],\n {\n isVerbose: true,\n }\n );\n\n for (const targetUnmergedDictionary of targetUnmergedDictionaries) {\n const dictionaryKey = targetUnmergedDictionary.key;\n const mainDictionaryToProcess = dictionariesRecord[dictionaryKey];\n const sourceLocale: Locales =\n (targetUnmergedDictionary.locale as Locales) ?? baseLocale;\n\n if (!mainDictionaryToProcess) {\n appLogger(\n `Dictionary with key \"${dictionaryKey}\" not found in dictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n appLogger(\n `Processing content declaration: ${targetUnmergedDictionary.filePath}`,\n {\n isVerbose: true,\n }\n );\n\n const sourceLocaleContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n if (Object.keys(sourceLocaleContent).length === 0) {\n appLogger(\n `No content found for dictionary ${dictionaryKey} in source locale ${sourceLocale}. Skipping translation for this dictionary.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n const result: Dictionary[] = [];\n\n // 5. for each locale to translate (exclude base locale) generate json translations\n for await (const targetLocale of outputLocalesList) {\n appLogger(\n `Preparing translation for ${dictionaryKey} from ${sourceLocale} to ${targetLocale}`,\n {\n isVerbose: true,\n }\n );\n\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n targetLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n try {\n const translationResult = await getAiAPI(\n undefined,\n configuration\n ).translateJSON(\n {\n entryFileContent: sourceLocaleContent.content, // Should be JSON, ensure getLocalisedContent provides this.\n presetOutputContent: presetOutputContent.content, // Should be JSON\n dictionaryDescription: mainDictionaryToProcess.description,\n entryLocale: sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions: options.aiOptions,\n },\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n if (!translationResult.data?.fileContent) {\n appLogger(\n `No content result found for ${dictionaryKey} to ${targetLocale}`,\n {\n level: 'error',\n }\n );\n continue;\n }\n\n const processedPerLocaleDictionary = processPerLocaleDictionary({\n ...mainDictionaryToProcess,\n content: translationResult.data?.fileContent,\n locale: targetLocale,\n });\n\n result.push(processedPerLocaleDictionary);\n } catch (error) {\n appLogger(\n `Error filling ${dictionaryKey} to ${targetLocale}:` + error,\n {\n level: 'error',\n }\n );\n }\n }\n\n const dictionaryToMerge =\n mode === 'review'\n ? [...result, mainDictionaryToProcess] // Mode review: generated content will override the base one\n : [mainDictionaryToProcess, ...result]; // Mode complete: base content will override the generated one\n\n const mergedResults = mergeDictionaries(dictionaryToMerge);\n\n let formattedDict = targetUnmergedDictionary;\n\n if (formattedDict.locale) {\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n formattedDict.locale,\n { dictionaryKey, keyPath: [] }\n );\n formattedDict = {\n ...formattedDict,\n content: presetOutputContent.content,\n };\n }\n\n const reducedResult = reduceDictionaryContent(mergedResults, formattedDict);\n\n await writeContentDeclaration(\n { ...formattedDict, content: reducedResult.content },\n configuration,\n formattedDict.filePath\n );\n\n await autoFill(\n mergedResults,\n targetUnmergedDictionary,\n formattedDict.autoFill,\n outputLocalesList,\n [sourceLocale],\n configuration\n );\n }\n};\n"],"mappings":"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","names":["localeList"]}
1
+ {"version":3,"sources":["../../src/fill.ts"],"sourcesContent":["import { AIOptions, getAiAPI } from '@intlayer/api'; // Importing only getAiAPI for now\nimport {\n getFilteredLocalesContent,\n listGitFiles,\n ListGitFilesOptions,\n mergeDictionaries,\n processPerLocaleDictionary,\n reduceDictionaryContent,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n type IntlayerConfig,\n Locales,\n} from '@intlayer/config';\nimport {\n type AutoFill,\n type ContentNode,\n type Dictionary,\n getLocalisedContent,\n} from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport unmergedDictionariesRecord from '@intlayer/unmerged-dictionaries-entry';\nimport { dirname, extname, join } from 'path';\nimport { getOAuthAPI } from '../../api/dist/types/getIntlayerAPI/oAuth';\nimport { checkAIAccess } from './utils/checkAIAccess';\n\n// Arguments for the fill function\nexport type FillOptions = {\n sourceLocale?: Locales;\n outputLocales?: Locales | Locales[];\n file?: string | string[];\n mode?: 'complete' | 'review';\n keys?: string | string[];\n excludedKeys?: string | string[];\n filter?: (entry: Dictionary) => boolean; // DictionaryEntry needs to be defined\n pathFilter?: string | string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n aiOptions?: AIOptions; // Added aiOptions to be passed to translateJSON\n verbose?: boolean;\n};\n\nconst ensureArray = <T>(value: T | T[]): T[] => [value].flat() as T[];\n\nconst getTargetDictionary = async (options: FillOptions) => {\n const configuration = getConfiguration(options.configOptions);\n\n const { baseDir } = configuration.content;\n\n let result = Object.values(unmergedDictionariesRecord).flat();\n\n // 1. if filePath not defined, list all content declaration files based on unmerged dictionaries list\n if (typeof options.file !== 'undefined') {\n const fileArray = ensureArray(options.file);\n const absoluteFilePaths = fileArray.map((file) => join(baseDir, file));\n\n result = result.filter(\n (dict) =>\n dict.filePath &&\n (absoluteFilePaths.includes(dict.filePath) ||\n absoluteFilePaths.includes(join(baseDir, dict.filePath)))\n );\n }\n\n if (typeof options.keys !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.keys)?.includes(dict.key)\n );\n }\n\n if (typeof options.excludedKeys !== 'undefined') {\n result = result.filter(\n (dict) => !ensureArray(options.excludedKeys)?.includes(dict.key)\n );\n }\n\n if (typeof options.pathFilter !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.pathFilter)?.includes(dict.filePath ?? '')\n );\n }\n\n if (typeof options.filter !== 'undefined') {\n result = result.filter(options.filter);\n }\n\n const gitOptions = options.gitOptions;\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n result = result.filter((dict) => {\n if (!dict.filePath) return false;\n\n return gitChangedFiles.some((gitFile) => dict.filePath === gitFile);\n });\n }\n }\n\n return result.filter((dict) => !dict.autoFilled);\n};\n\nconst transformUriToAbsolutePath = (\n uri: string,\n filePath: string,\n baseDir: string\n) => {\n if (uri.startsWith('/')) {\n return join(baseDir, uri);\n }\n\n if (uri.startsWith('./')) {\n return join(dirname(filePath), uri);\n }\n\n return filePath;\n};\n\nexport type AutoFillData = {\n localeList: Locales[];\n filePath: string;\n};\n\nconst formatAutoFillData = (\n autoFillOptions: AutoFill,\n localeList: Locales[],\n filePath: string,\n dictionaryKey: string,\n configuration: IntlayerConfig\n): AutoFillData[] => {\n const outputContentDeclarationFile: AutoFillData[] = [];\n\n if (!Boolean(autoFillOptions)) return outputContentDeclarationFile;\n\n if (autoFillOptions === true) {\n // wanted jsonFilePath: /..../src/components/home/index.content.json\n // replace file extension in json\n let jsonFilePath = filePath.replace(extname(filePath), '.json');\n\n // if both filePath jsonFilePath are same path, change it as : /..../src/components/home/index.fill.content.json\n if (filePath === jsonFilePath) {\n jsonFilePath = jsonFilePath.replace(extname(jsonFilePath), '.fill.json');\n }\n\n outputContentDeclarationFile.push({\n localeList,\n filePath: jsonFilePath,\n });\n }\n\n if (typeof autoFillOptions === 'string') {\n if (autoFillOptions.includes('{{locale}}')) {\n const output = localeList.map((locale) => ({\n localeList: [locale],\n filePath: transformUriToAbsolutePath(\n autoFillOptions\n .replace('{{locale}}', locale)\n .replace('{{key}}', dictionaryKey),\n filePath,\n configuration.content.baseDir\n ),\n }));\n\n outputContentDeclarationFile.push(...output);\n } else {\n outputContentDeclarationFile.push({\n localeList,\n filePath: transformUriToAbsolutePath(\n autoFillOptions,\n filePath,\n configuration.content.baseDir\n ),\n });\n }\n\n return outputContentDeclarationFile;\n }\n\n if (typeof autoFillOptions === 'object') {\n const localeList = Object.keys(autoFillOptions).filter(\n (locale) => typeof autoFillOptions[locale] === 'string'\n ) as Locales[];\n\n const output: AutoFillData[] = localeList.map((locale) => ({\n localeList: [locale],\n filePath: transformUriToAbsolutePath(\n autoFillOptions[locale].replace('{{key}}', dictionaryKey),\n filePath,\n configuration.content.baseDir\n ),\n }));\n\n // Group by filePath and merge localeList\n const groupedByFilePath = output.reduce((acc, curr) => {\n const existing = acc.find((item) => item.filePath === curr.filePath);\n if (existing) {\n existing.localeList.push(...curr.localeList);\n } else {\n acc.push(curr);\n }\n return acc;\n }, [] as AutoFillData[]);\n\n outputContentDeclarationFile.push(...groupedByFilePath);\n }\n\n return outputContentDeclarationFile;\n};\n\nconst autoFill = async (\n fullDictionary: Dictionary,\n contentDeclarationFile: Dictionary,\n autoFillOptions: AutoFill,\n outputLocales: Locales[],\n parentLocales: Locales[],\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n let localeList: Locales[] = (\n outputLocales ?? configuration.internationalization.locales\n ).filter((locale) => !parentLocales?.includes(locale));\n\n const filePath = contentDeclarationFile.filePath;\n\n if (!filePath) {\n appLogger('No file path found for dictionary', {\n level: 'error',\n });\n return;\n }\n\n const autoFillData: AutoFillData[] = formatAutoFillData(\n autoFillOptions,\n localeList,\n filePath,\n fullDictionary.key,\n configuration\n );\n\n appLogger(`Auto fill data: ${JSON.stringify(autoFillData, null, 2)}`, {\n level: 'info',\n isVerbose: true,\n });\n\n for await (const output of autoFillData) {\n const reducedDictionary = reduceDictionaryContent(\n fullDictionary,\n contentDeclarationFile\n );\n\n const isPerLocaleDeclarationFile = output.localeList.length === 1;\n\n if (isPerLocaleDeclarationFile) {\n const sourceLocale = output.localeList[0];\n\n const sourceLocaleContent = getLocalisedContent(\n reducedDictionary as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n await writeContentDeclaration({\n ...fullDictionary,\n locale: sourceLocale,\n autoFilled: true,\n autoFill: undefined,\n content: sourceLocaleContent.content,\n filePath: output.filePath,\n });\n } else {\n const content = getFilteredLocalesContent(\n reducedDictionary.content as unknown as ContentNode,\n output.localeList,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n // write file\n await writeContentDeclaration({\n ...fullDictionary,\n autoFilled: true,\n autoFill: undefined,\n content,\n filePath: output.filePath,\n });\n }\n }\n};\n\n/**\n * Fill translations based on the provided options.\n */\nexport const fill = async (options: FillOptions): Promise<void> => {\n const configuration = getConfiguration(options.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const { defaultLocale, locales } = configuration.internationalization;\n const mode = options.mode ?? 'review';\n const baseLocale = options.sourceLocale ?? defaultLocale;\n\n checkAIAccess(configuration, options.aiOptions);\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getOAuthAPI(configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger('Starting fill function', {\n level: 'info',\n });\n\n const targetUnmergedDictionaries = await getTargetDictionary(options);\n\n // Determine output locales\n const outputLocalesList: Locales[] = (\n options.outputLocales ? ensureArray(options.outputLocales) : locales\n ).filter((locale) =>\n // If mode is review, translate all locales\n // If mode is complete, translate only the locales that are not the source locale\n mode === 'review' ? true : locale !== baseLocale\n );\n\n const affectedDictionaryKeys = new Set<string>();\n targetUnmergedDictionaries.forEach((dict) => {\n affectedDictionaryKeys.add(dict.key);\n });\n\n appLogger(\n [\n 'Affected dictionary keys for processing:',\n Array.from(affectedDictionaryKeys).join(', '),\n ],\n {\n isVerbose: true,\n }\n );\n\n for (const targetUnmergedDictionary of targetUnmergedDictionaries) {\n const dictionaryKey = targetUnmergedDictionary.key;\n const mainDictionaryToProcess = dictionariesRecord[dictionaryKey];\n const sourceLocale: Locales =\n (targetUnmergedDictionary.locale as Locales) ?? baseLocale;\n\n if (!mainDictionaryToProcess) {\n appLogger(\n `Dictionary with key \"${dictionaryKey}\" not found in dictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n appLogger(\n `Processing content declaration: ${targetUnmergedDictionary.filePath}`,\n {\n isVerbose: true,\n }\n );\n\n const sourceLocaleContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n if (Object.keys(sourceLocaleContent).length === 0) {\n appLogger(\n `No content found for dictionary ${dictionaryKey} in source locale ${sourceLocale}. Skipping translation for this dictionary.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n const result: Dictionary[] = [];\n\n // 5. for each locale to translate (exclude base locale) generate json translations\n for await (const targetLocale of outputLocalesList) {\n appLogger(\n `Preparing translation for ${dictionaryKey} from ${sourceLocale} to ${targetLocale}`,\n {\n isVerbose: true,\n }\n );\n\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n targetLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n try {\n const translationResult = await getAiAPI(\n undefined,\n configuration\n ).translateJSON(\n {\n entryFileContent: sourceLocaleContent.content, // Should be JSON, ensure getLocalisedContent provides this.\n presetOutputContent: presetOutputContent.content, // Should be JSON\n dictionaryDescription: mainDictionaryToProcess.description,\n entryLocale: sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions: options.aiOptions,\n },\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n if (!translationResult.data?.fileContent) {\n appLogger(\n `No content result found for ${dictionaryKey} to ${targetLocale}`,\n {\n level: 'error',\n }\n );\n continue;\n }\n\n const processedPerLocaleDictionary = processPerLocaleDictionary({\n ...mainDictionaryToProcess,\n content: translationResult.data?.fileContent,\n locale: targetLocale,\n });\n\n result.push(processedPerLocaleDictionary);\n } catch (error) {\n appLogger(\n `Error filling ${dictionaryKey} to ${targetLocale}:` + error,\n {\n level: 'error',\n }\n );\n }\n }\n\n const dictionaryToMerge =\n mode === 'review'\n ? [...result, mainDictionaryToProcess] // Mode review: generated content will override the base one\n : [mainDictionaryToProcess, ...result]; // Mode complete: base content will override the generated one\n\n const mergedResults = mergeDictionaries(dictionaryToMerge);\n\n let formattedDict = targetUnmergedDictionary;\n\n if (formattedDict.locale) {\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n formattedDict.locale,\n { dictionaryKey, keyPath: [] }\n );\n formattedDict = {\n ...formattedDict,\n content: presetOutputContent.content,\n };\n }\n\n const reducedResult = reduceDictionaryContent(mergedResults, formattedDict);\n\n await writeContentDeclaration(\n { ...formattedDict, content: reducedResult.content },\n configuration,\n formattedDict.filePath\n );\n\n await autoFill(\n mergedResults,\n targetUnmergedDictionary,\n formattedDict.autoFill,\n outputLocalesList,\n [sourceLocale],\n configuration\n );\n }\n};\n"],"mappings":"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","names":["localeList"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './build';\nexport * from './cli';\nexport * from './fill';\nexport * from './listContentDeclaration';\nexport * from './pull';\nexport * from './push';\nexport * from './pushConfig';\nexport * from './reviewDoc';\nexport * from './translateDoc';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export type * from '@intlayer/chokidar';\nexport * from './build';\nexport * from './cli';\nexport * from './fill';\nexport * from './listContentDeclaration';\nexport * from './pull';\nexport * from './push';\nexport * from './pushConfig';\nexport * from './reviewDoc';\nexport * from './translateDoc';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
package/dist/esm/pull.mjs CHANGED
@@ -27,7 +27,7 @@ const pull = async (options) => {
27
27
  );
28
28
  }
29
29
  const intlayerAPI = getIntlayerAPI(void 0, config);
30
- const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();
30
+ const oAuth2TokenResult = await intlayerAPI.oAuth.getOAuth2AccessToken();
31
31
  const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
32
32
  const getDictionariesKeysResult = await intlayerAPI.dictionary.getDictionariesKeys({
33
33
  ...oAuth2AccessToken && {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import { getIntlayerAPI } from '@intlayer/api';\nimport {\n writeContentDeclaration,\n type DictionaryStatus,\n} from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n} from '@intlayer/config';\n\nimport type { Dictionary } from '@intlayer/core';\nimport pLimit from 'p-limit';\nimport * as readline from 'readline';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus;\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import { getIntlayerAPI } from '@intlayer/api';\nimport {\n writeContentDeclaration,\n type DictionaryStatus,\n} from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n} from '@intlayer/config';\n\nimport type { Dictionary } from '@intlayer/core';\nimport pLimit from 'p-limit';\nimport * as readline from 'readline';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus;\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.oAuth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":[]}