@intlayer/cli 4.1.4 → 4.1.5

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 (47) hide show
  1. package/dist/cjs/audit.cjs +21 -4
  2. package/dist/cjs/audit.cjs.map +1 -1
  3. package/dist/cjs/cli.cjs +7 -3
  4. package/dist/cjs/cli.cjs.map +1 -1
  5. package/dist/cjs/config.cjs +6 -2
  6. package/dist/cjs/config.cjs.map +1 -1
  7. package/dist/cjs/index.cjs +3 -1
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/listContentDeclaration.cjs +6 -2
  10. package/dist/cjs/listContentDeclaration.cjs.map +1 -1
  11. package/dist/cjs/pull.cjs +23 -4
  12. package/dist/cjs/pull.cjs.map +1 -1
  13. package/dist/cjs/push.cjs +55 -13
  14. package/dist/cjs/push.cjs.map +1 -1
  15. package/dist/cjs/pushConfig.cjs +65 -0
  16. package/dist/cjs/pushConfig.cjs.map +1 -0
  17. package/dist/esm/audit.mjs +21 -4
  18. package/dist/esm/audit.mjs.map +1 -1
  19. package/dist/esm/cli.mjs +7 -3
  20. package/dist/esm/cli.mjs.map +1 -1
  21. package/dist/esm/config.mjs +6 -2
  22. package/dist/esm/config.mjs.map +1 -1
  23. package/dist/esm/index.mjs +1 -0
  24. package/dist/esm/index.mjs.map +1 -1
  25. package/dist/esm/listContentDeclaration.mjs +6 -2
  26. package/dist/esm/listContentDeclaration.mjs.map +1 -1
  27. package/dist/esm/pull.mjs +23 -4
  28. package/dist/esm/pull.mjs.map +1 -1
  29. package/dist/esm/push.mjs +55 -13
  30. package/dist/esm/push.mjs.map +1 -1
  31. package/dist/esm/pushConfig.mjs +41 -0
  32. package/dist/esm/pushConfig.mjs.map +1 -0
  33. package/dist/types/audit.d.ts +1 -0
  34. package/dist/types/audit.d.ts.map +1 -1
  35. package/dist/types/cli.d.ts.map +1 -1
  36. package/dist/types/config.d.ts +4 -2
  37. package/dist/types/config.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/listContentDeclaration.d.ts +4 -2
  41. package/dist/types/listContentDeclaration.d.ts.map +1 -1
  42. package/dist/types/pull.d.ts.map +1 -1
  43. package/dist/types/push.d.ts +1 -0
  44. package/dist/types/push.d.ts.map +1 -1
  45. package/dist/types/pushConfig.d.ts +7 -0
  46. package/dist/types/pushConfig.d.ts.map +1 -0
  47. package/package.json +14 -14
@@ -43,7 +43,11 @@ const auditFile = async (filePath, options) => {
43
43
  try {
44
44
  const { defaultLocale, locales } = (0, import_config.getConfiguration)().internationalization;
45
45
  const relativePath = (0, import_path.relative)(projectPath, filePath);
46
- (0, import_config.logger)(`Auditing file: ${relativePath}`);
46
+ (0, import_config.logger)(`Auditing file: ${relativePath}`, {
47
+ config: {
48
+ prefix: options?.logPrefix
49
+ }
50
+ });
47
51
  const fileContent = (0, import_fs.readFileSync)(filePath, "utf-8");
48
52
  const auditFileResult = await import_api.intlayerAPI.ai.auditContentDeclaration(
49
53
  {
@@ -63,10 +67,23 @@ const auditFile = async (filePath, options) => {
63
67
  throw new Error("Audit failed");
64
68
  }
65
69
  (0, import_fs.writeFileSync)(filePath, auditFileResult.data.fileContent);
66
- (0, import_config.logger)(`File ${relativePath} updated`);
67
- (0, import_config.logger)(`${auditFileResult.data.tokenUsed} tokens used in the request`);
70
+ (0, import_config.logger)(`File ${relativePath} updated`, {
71
+ config: {
72
+ prefix: options?.logPrefix
73
+ }
74
+ });
75
+ (0, import_config.logger)(`${auditFileResult.data.tokenUsed} tokens used in the request`, {
76
+ config: {
77
+ prefix: options?.logPrefix
78
+ }
79
+ });
68
80
  } catch (error) {
69
- (0, import_config.logger)(error, { level: "error" });
81
+ (0, import_config.logger)(error, {
82
+ level: "error",
83
+ config: {
84
+ prefix: options?.logPrefix
85
+ }
86
+ });
70
87
  }
71
88
  };
72
89
  const getAbsolutePath = (filePath) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/audit.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'fs';\nimport { join, relative } from 'path';\nimport { intlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport pLimit from 'p-limit';\nimport { getContentDeclaration } from './listContentDeclaration';\n\n// Depending on your implementation, you may need the OpenAI API client.\n// For instance, you can use `openai` npm package (https://www.npmjs.com/package/openai).\n\ntype AuditOptions = {\n files?: string[];\n model?: string;\n customPrompt?: string;\n asyncLimit?: number;\n openAiApiKey?: string;\n excludedGlobs?: string[];\n headers?: Record<string, string>;\n};\n\nconst projectPath = process.cwd();\n\n/**\n * Audits a content declaration file by constructing a prompt for ChatGPT.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies. It prints the prompt for each file,\n * and could be adapted to send requests to the ChatGPT model.\n *\n * @async\n * @function\n * @param filePath - The relative or absolute path to the target file.\n * @param options - Optional configuration for the audit process.\n * @returns This function returns a Promise that resolves once the audit is complete.\n */\nexport const auditFile = async (filePath: string, options?: AuditOptions) => {\n try {\n const { defaultLocale, locales } = getConfiguration().internationalization;\n\n const relativePath = relative(projectPath, filePath);\n logger(`Auditing file: ${relativePath}`);\n\n // Read the file's content.\n const fileContent = readFileSync(filePath, 'utf-8');\n\n // Example of how you might request a completion from ChatGPT:\n const auditFileResult = await intlayerAPI.ai.auditContentDeclaration(\n {\n fileContent,\n filePath,\n locales,\n defaultLocale,\n model: options?.model,\n openAiApiKey: options?.openAiApiKey,\n customPrompt: options?.customPrompt,\n },\n {\n headers: options?.headers,\n }\n );\n\n if (!auditFileResult.data) {\n throw new Error('Audit failed');\n }\n\n writeFileSync(filePath, auditFileResult.data.fileContent);\n\n logger(`File ${relativePath} updated`);\n\n logger(`${auditFileResult.data.tokenUsed} tokens used in the request`);\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst getAbsolutePath = (filePath: string): string => {\n if (filePath.startsWith('.')) {\n const absolutePath = join(process.cwd(), filePath);\n\n return absolutePath;\n }\n return filePath;\n};\n\n/**\n * Audits the content declaration files by constructing a prompt for ChatGPT.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies. It prints the prompt for each file,\n * and could be adapted to send requests to the ChatGPT model.\n *\n * @async\n * @function\n * @param options - Optional configuration for the audit process.\n * @returns This function returns a Promise that resolves once the audit is complete.\n */\nexport const audit = async (options: AuditOptions) => {\n const { clientId, clientSecret } = getConfiguration().editor;\n let headers: Record<string, string> = {};\n\n if (clientId && clientSecret) {\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n headers = { Authorization: `Bearer ${oAuth2AccessToken}` };\n } else if (!options?.openAiApiKey) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project. You can also provide your own OpenAI API key to audit the content declaration files. For that you need to provide the --openAiApiKey option.'\n );\n }\n\n let contentDeclarationFilesList = options?.files?.map(getAbsolutePath);\n\n if (!contentDeclarationFilesList) {\n // Retrieve all content declaration file paths using a helper function.\n const contentDeclarationFilesPath = getContentDeclaration({\n exclude: options?.excludedGlobs,\n });\n\n contentDeclarationFilesList = contentDeclarationFilesPath;\n }\n\n const limit = pLimit(options?.asyncLimit ? Number(options?.asyncLimit) : 5); // Limit the number of concurrent requests\n const pushPromises = contentDeclarationFilesList.map((filePath) =>\n limit(() => auditFile(filePath, { ...options, headers }))\n );\n await Promise.all(pushPromises);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAA4C;AAC5C,kBAA+B;AAC/B,iBAA4B;AAC5B,oBAAyC;AACzC,qBAAmB;AACnB,oCAAsC;AAetC,MAAM,cAAc,QAAQ,IAAI;AAczB,MAAM,YAAY,OAAO,UAAkB,YAA2B;AAC3E,MAAI;AACF,UAAM,EAAE,eAAe,QAAQ,QAAI,gCAAiB,EAAE;AAEtD,UAAM,mBAAe,sBAAS,aAAa,QAAQ;AACnD,8BAAO,kBAAkB,YAAY,EAAE;AAGvC,UAAM,kBAAc,wBAAa,UAAU,OAAO;AAGlD,UAAM,kBAAkB,MAAM,uBAAY,GAAG;AAAA,MAC3C;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,SAAS;AAAA,QAChB,cAAc,SAAS;AAAA,QACvB,cAAc,SAAS;AAAA,MACzB;AAAA,MACA;AAAA,QACE,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,CAAC,gBAAgB,MAAM;AACzB,YAAM,IAAI,MAAM,cAAc;AAAA,IAChC;AAEA,iCAAc,UAAU,gBAAgB,KAAK,WAAW;AAExD,8BAAO,QAAQ,YAAY,UAAU;AAErC,8BAAO,GAAG,gBAAgB,KAAK,SAAS,6BAA6B;AAAA,EACvE,SAAS,OAAO;AACd,8BAAO,OAAO,EAAE,OAAO,QAAQ,CAAC;AAAA,EAClC;AACF;AAEA,MAAM,kBAAkB,CAAC,aAA6B;AACpD,MAAI,SAAS,WAAW,GAAG,GAAG;AAC5B,UAAM,mBAAe,kBAAK,QAAQ,IAAI,GAAG,QAAQ;AAEjD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAaO,MAAM,QAAQ,OAAO,YAA0B;AACpD,QAAM,EAAE,UAAU,aAAa,QAAI,gCAAiB,EAAE;AACtD,MAAI,UAAkC,CAAC;AAEvC,MAAI,YAAY,cAAc;AAC5B,UAAM,oBAAoB,MAAM,uBAAY,KAAK,qBAAqB;AAEtE,UAAM,oBAAoB,kBAAkB,MAAM;AAElD,cAAU,EAAE,eAAe,UAAU,iBAAiB,GAAG;AAAA,EAC3D,WAAW,CAAC,SAAS,cAAc;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,8BAA8B,SAAS,OAAO,IAAI,eAAe;AAErE,MAAI,CAAC,6BAA6B;AAEhC,UAAM,kCAA8B,qDAAsB;AAAA,MACxD,SAAS,SAAS;AAAA,IACpB,CAAC;AAED,kCAA8B;AAAA,EAChC;AAEA,QAAM,YAAQ,eAAAA,SAAO,SAAS,aAAa,OAAO,SAAS,UAAU,IAAI,CAAC;AAC1E,QAAM,eAAe,4BAA4B;AAAA,IAAI,CAAC,aACpD,MAAM,MAAM,UAAU,UAAU,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,EAC1D;AACA,QAAM,QAAQ,IAAI,YAAY;AAChC;","names":["pLimit"]}
1
+ {"version":3,"sources":["../../src/audit.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'fs';\nimport { join, relative } from 'path';\nimport { intlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport pLimit from 'p-limit';\nimport { getContentDeclaration } from './listContentDeclaration';\n\n// Depending on your implementation, you may need the OpenAI API client.\n// For instance, you can use `openai` npm package (https://www.npmjs.com/package/openai).\n\ntype AuditOptions = {\n files?: string[];\n model?: string;\n customPrompt?: string;\n asyncLimit?: number;\n openAiApiKey?: string;\n excludedGlobs?: string[];\n headers?: Record<string, string>;\n logPrefix?: string;\n};\n\nconst projectPath = process.cwd();\n\n/**\n * Audits a content declaration file by constructing a prompt for ChatGPT.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies. It prints the prompt for each file,\n * and could be adapted to send requests to the ChatGPT model.\n *\n * @async\n * @function\n * @param filePath - The relative or absolute path to the target file.\n * @param options - Optional configuration for the audit process.\n * @returns This function returns a Promise that resolves once the audit is complete.\n */\nexport const auditFile = async (filePath: string, options?: AuditOptions) => {\n try {\n const { defaultLocale, locales } = getConfiguration().internationalization;\n\n const relativePath = relative(projectPath, filePath);\n logger(`Auditing file: ${relativePath}`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n // Read the file's content.\n const fileContent = readFileSync(filePath, 'utf-8');\n\n // Example of how you might request a completion from ChatGPT:\n const auditFileResult = await intlayerAPI.ai.auditContentDeclaration(\n {\n fileContent,\n filePath,\n locales,\n defaultLocale,\n model: options?.model,\n openAiApiKey: options?.openAiApiKey,\n customPrompt: options?.customPrompt,\n },\n {\n headers: options?.headers,\n }\n );\n\n if (!auditFileResult.data) {\n throw new Error('Audit failed');\n }\n\n writeFileSync(filePath, auditFileResult.data.fileContent);\n\n logger(`File ${relativePath} updated`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n logger(`${auditFileResult.data.tokenUsed} tokens used in the request`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n } catch (error) {\n logger(error, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n};\n\nconst getAbsolutePath = (filePath: string): string => {\n if (filePath.startsWith('.')) {\n const absolutePath = join(process.cwd(), filePath);\n\n return absolutePath;\n }\n return filePath;\n};\n\n/**\n * Audits the content declaration files by constructing a prompt for ChatGPT.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies. It prints the prompt for each file,\n * and could be adapted to send requests to the ChatGPT model.\n *\n * @async\n * @function\n * @param options - Optional configuration for the audit process.\n * @returns This function returns a Promise that resolves once the audit is complete.\n */\nexport const audit = async (options: AuditOptions) => {\n const { clientId, clientSecret } = getConfiguration().editor;\n let headers: Record<string, string> = {};\n\n if (clientId && clientSecret) {\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n headers = { Authorization: `Bearer ${oAuth2AccessToken}` };\n } else if (!options?.openAiApiKey) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project. You can also provide your own OpenAI API key to audit the content declaration files. For that you need to provide the --openAiApiKey option.'\n );\n }\n\n let contentDeclarationFilesList = options?.files?.map(getAbsolutePath);\n\n if (!contentDeclarationFilesList) {\n // Retrieve all content declaration file paths using a helper function.\n const contentDeclarationFilesPath = getContentDeclaration({\n exclude: options?.excludedGlobs,\n });\n\n contentDeclarationFilesList = contentDeclarationFilesPath;\n }\n\n const limit = pLimit(options?.asyncLimit ? Number(options?.asyncLimit) : 5); // Limit the number of concurrent requests\n const pushPromises = contentDeclarationFilesList.map((filePath) =>\n limit(() => auditFile(filePath, { ...options, headers }))\n );\n await Promise.all(pushPromises);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAA4C;AAC5C,kBAA+B;AAC/B,iBAA4B;AAC5B,oBAAyC;AACzC,qBAAmB;AACnB,oCAAsC;AAgBtC,MAAM,cAAc,QAAQ,IAAI;AAczB,MAAM,YAAY,OAAO,UAAkB,YAA2B;AAC3E,MAAI;AACF,UAAM,EAAE,eAAe,QAAQ,QAAI,gCAAiB,EAAE;AAEtD,UAAM,mBAAe,sBAAS,aAAa,QAAQ;AACnD,8BAAO,kBAAkB,YAAY,IAAI;AAAA,MACvC,QAAQ;AAAA,QACN,QAAQ,SAAS;AAAA,MACnB;AAAA,IACF,CAAC;AAGD,UAAM,kBAAc,wBAAa,UAAU,OAAO;AAGlD,UAAM,kBAAkB,MAAM,uBAAY,GAAG;AAAA,MAC3C;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,SAAS;AAAA,QAChB,cAAc,SAAS;AAAA,QACvB,cAAc,SAAS;AAAA,MACzB;AAAA,MACA;AAAA,QACE,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,CAAC,gBAAgB,MAAM;AACzB,YAAM,IAAI,MAAM,cAAc;AAAA,IAChC;AAEA,iCAAc,UAAU,gBAAgB,KAAK,WAAW;AAExD,8BAAO,QAAQ,YAAY,YAAY;AAAA,MACrC,QAAQ;AAAA,QACN,QAAQ,SAAS;AAAA,MACnB;AAAA,IACF,CAAC;AAED,8BAAO,GAAG,gBAAgB,KAAK,SAAS,+BAA+B;AAAA,MACrE,QAAQ;AAAA,QACN,QAAQ,SAAS;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,8BAAO,OAAO;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,QACN,QAAQ,SAAS;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,MAAM,kBAAkB,CAAC,aAA6B;AACpD,MAAI,SAAS,WAAW,GAAG,GAAG;AAC5B,UAAM,mBAAe,kBAAK,QAAQ,IAAI,GAAG,QAAQ;AAEjD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAaO,MAAM,QAAQ,OAAO,YAA0B;AACpD,QAAM,EAAE,UAAU,aAAa,QAAI,gCAAiB,EAAE;AACtD,MAAI,UAAkC,CAAC;AAEvC,MAAI,YAAY,cAAc;AAC5B,UAAM,oBAAoB,MAAM,uBAAY,KAAK,qBAAqB;AAEtE,UAAM,oBAAoB,kBAAkB,MAAM;AAElD,cAAU,EAAE,eAAe,UAAU,iBAAiB,GAAG;AAAA,EAC3D,WAAW,CAAC,SAAS,cAAc;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,8BAA8B,SAAS,OAAO,IAAI,eAAe;AAErE,MAAI,CAAC,6BAA6B;AAEhC,UAAM,kCAA8B,qDAAsB;AAAA,MACxD,SAAS,SAAS;AAAA,IACpB,CAAC;AAED,kCAA8B;AAAA,EAChC;AAEA,QAAM,YAAQ,eAAAA,SAAO,SAAS,aAAa,OAAO,SAAS,UAAU,IAAI,CAAC;AAC1E,QAAM,eAAe,4BAA4B;AAAA,IAAI,CAAC,aACpD,MAAM,MAAM,UAAU,UAAU,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,EAC1D;AACA,QAAM,QAAQ,IAAI,YAAY;AAChC;","names":["pLimit"]}
package/dist/cjs/cli.cjs CHANGED
@@ -28,11 +28,14 @@ var import_config = require('./config.cjs');
28
28
  var import_listContentDeclaration = require('./listContentDeclaration.cjs');
29
29
  var import_pull = require('./pull.cjs');
30
30
  var import_push = require('./push.cjs');
31
+ var import_pushConfig = require('./pushConfig.cjs');
31
32
  const setAPI = () => {
32
33
  const program = new import_commander.Command();
33
34
  program.version("1.0.0").description("Intlayer CLI");
34
35
  program.command("build").description("Build the dictionaries").option("-w, --watch", "Watch for changes").action(import_build.build);
35
- program.command("push").description(
36
+ const dictionariesProgram = program.command("dictionaries").description("Dictionaries operations");
37
+ dictionariesProgram.command("pull").option("-d, --dictionaries [ids...]", "List of dictionary IDs to pull").option("--newDictionariesPath [path]", "Path to save the new dictionaries").action(import_pull.pull);
38
+ dictionariesProgram.command("push").description(
36
39
  "Push all dictionaries. Create or update the pushed dictionaries"
37
40
  ).option("-d, --dictionaries [ids...]", "List of dictionary IDs to push").option(
38
41
  "-r, --deleteLocaleDictionary",
@@ -41,8 +44,9 @@ const setAPI = () => {
41
44
  "-k, --keepLocaleDictionary",
42
45
  "Keep the local dictionaries after pushing"
43
46
  ).action(import_push.push);
44
- program.command("pull").option("-d, --dictionaries [ids...]", "List of dictionary IDs to pull").option("--newDictionariesPath [path]", "Path to save the new dictionaries").action(import_pull.pull);
45
- program.command("get config").description("Get the configuration").action(import_config.getConfig);
47
+ const configurationProgram = program.command("config").description("Configuration operations");
48
+ configurationProgram.command("get").description("Get the configuration").action(import_config.getConfig);
49
+ configurationProgram.command("push").description("Push the configuration").action(import_pushConfig.pushConfig);
46
50
  program.command("content list").description("List the content declaration files").action(import_listContentDeclaration.listContentDeclaration);
47
51
  program.command("audit").description("Audit the dictionaries").option(
48
52
  "-f, --files [files...]",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { audit } from './audit';\nimport { build } from './build';\nimport { getConfig } from './config';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { pull } from './pull';\nimport { push } from './push';\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('1.0.0').description('Intlayer CLI');\n\n program\n .command('build')\n .description('Build the dictionaries')\n .option('-w, --watch', 'Watch for changes')\n .action(build);\n\n program\n .command('push')\n .description(\n 'Push all dictionaries. Create or update the pushed dictionaries'\n )\n .option('-d, --dictionaries [ids...]', 'List of dictionary IDs to push')\n .option(\n '-r, --deleteLocaleDictionary',\n 'Delete the local dictionaries after pushing'\n )\n .option(\n '-k, --keepLocaleDictionary',\n 'Keep the local dictionaries after pushing'\n )\n .action(push);\n\n program\n .command('pull')\n .option('-d, --dictionaries [ids...]', 'List of dictionary IDs to pull')\n .option('--newDictionariesPath [path]', 'Path to save the new dictionaries')\n .action(pull);\n\n program\n .command('get config')\n .description('Get the configuration')\n .action(getConfig);\n\n program\n .command('content list')\n .description('List the content declaration files')\n .action(listContentDeclaration);\n\n program\n .command('audit')\n .description('Audit the dictionaries')\n .option(\n '-f, --files [files...]',\n 'List of Content Declaration files to audit'\n )\n .option(\n '--exclude [excludedGlobs...]',\n 'Globs pattern to exclude from the audit'\n )\n .option('-m, --model [model]', 'Model')\n .option('-p, --custom-prompt [prompt]', 'Custom prompt')\n .option('-l, --async-limit [asyncLimit]', 'Async limit')\n .option('-k, --open-ai-api-key [openAiApiKey]', 'OpenAI API key')\n .action(audit);\n\n program.parse(process.argv);\n\n return program;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;AACxB,mBAAsB;AACtB,mBAAsB;AACtB,oBAA0B;AAC1B,oCAAuC;AACvC,kBAAqB;AACrB,kBAAqB;AAUd,MAAM,SAAS,MAAe;AACnC,QAAM,UAAU,IAAI,yBAAQ;AAE5B,UAAQ,QAAQ,OAAO,EAAE,YAAY,cAAc;AAEnD,UACG,QAAQ,OAAO,EACf,YAAY,wBAAwB,EACpC,OAAO,eAAe,mBAAmB,EACzC,OAAO,kBAAK;AAEf,UACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EACF,EACC,OAAO,+BAA+B,gCAAgC,EACtE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,gBAAI;AAEd,UACG,QAAQ,MAAM,EACd,OAAO,+BAA+B,gCAAgC,EACtE,OAAO,gCAAgC,mCAAmC,EAC1E,OAAO,gBAAI;AAEd,UACG,QAAQ,YAAY,EACpB,YAAY,uBAAuB,EACnC,OAAO,uBAAS;AAEnB,UACG,QAAQ,cAAc,EACtB,YAAY,oCAAoC,EAChD,OAAO,oDAAsB;AAEhC,UACG,QAAQ,OAAO,EACf,YAAY,wBAAwB,EACpC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,uBAAuB,OAAO,EACrC,OAAO,gCAAgC,eAAe,EACtD,OAAO,kCAAkC,aAAa,EACtD,OAAO,wCAAwC,gBAAgB,EAC/D,OAAO,kBAAK;AAEf,UAAQ,MAAM,QAAQ,IAAI;AAE1B,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { audit } from './audit';\nimport { build } from './build';\nimport { getConfig } from './config';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { pull } from './pull';\nimport { push } from './push';\nimport { pushConfig } from './pushConfig';\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('1.0.0').description('Intlayer CLI');\n\n program\n .command('build')\n .description('Build the dictionaries')\n .option('-w, --watch', 'Watch for changes')\n .action(build);\n\n /**\n * DICTIONARIES\n */\n\n const dictionariesProgram = program\n .command('dictionaries')\n .description('Dictionaries operations');\n\n dictionariesProgram\n .command('pull')\n .option('-d, --dictionaries [ids...]', 'List of dictionary IDs to pull')\n .option('--newDictionariesPath [path]', 'Path to save the new dictionaries')\n .action(pull);\n\n // Define the main `push` command\n dictionariesProgram\n .command('push')\n .description(\n 'Push all dictionaries. Create or update the pushed dictionaries'\n )\n .option('-d, --dictionaries [ids...]', 'List of dictionary IDs to push')\n .option(\n '-r, --deleteLocaleDictionary',\n 'Delete the local dictionaries after pushing'\n )\n .option(\n '-k, --keepLocaleDictionary',\n 'Keep the local dictionaries after pushing'\n )\n .action(push);\n\n /**\n * CONFIGURATION\n */\n\n const configurationProgram = program\n .command('config')\n .description('Configuration operations');\n\n configurationProgram\n .command('get')\n .description('Get the configuration')\n\n .action(getConfig);\n\n // Define the `push config` subcommand and add it to the `push` command\n configurationProgram\n .command('push')\n .description('Push the configuration')\n .action(pushConfig);\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 program\n .command('audit')\n .description('Audit the dictionaries')\n .option(\n '-f, --files [files...]',\n 'List of Content Declaration files to audit'\n )\n .option(\n '--exclude [excludedGlobs...]',\n 'Globs pattern to exclude from the audit'\n )\n .option('-m, --model [model]', 'Model')\n .option('-p, --custom-prompt [prompt]', 'Custom prompt')\n .option('-l, --async-limit [asyncLimit]', 'Async limit')\n .option('-k, --open-ai-api-key [openAiApiKey]', 'OpenAI API key')\n .action(audit);\n\n program.parse(process.argv);\n\n return program;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;AACxB,mBAAsB;AACtB,mBAAsB;AACtB,oBAA0B;AAC1B,oCAAuC;AACvC,kBAAqB;AACrB,kBAAqB;AACrB,wBAA2B;AAUpB,MAAM,SAAS,MAAe;AACnC,QAAM,UAAU,IAAI,yBAAQ;AAE5B,UAAQ,QAAQ,OAAO,EAAE,YAAY,cAAc;AAEnD,UACG,QAAQ,OAAO,EACf,YAAY,wBAAwB,EACpC,OAAO,eAAe,mBAAmB,EACzC,OAAO,kBAAK;AAMf,QAAM,sBAAsB,QACzB,QAAQ,cAAc,EACtB,YAAY,yBAAyB;AAExC,sBACG,QAAQ,MAAM,EACd,OAAO,+BAA+B,gCAAgC,EACtE,OAAO,gCAAgC,mCAAmC,EAC1E,OAAO,gBAAI;AAGd,sBACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EACF,EACC,OAAO,+BAA+B,gCAAgC,EACtE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,gBAAI;AAMd,QAAM,uBAAuB,QAC1B,QAAQ,QAAQ,EAChB,YAAY,0BAA0B;AAEzC,uBACG,QAAQ,KAAK,EACb,YAAY,uBAAuB,EAEnC,OAAO,uBAAS;AAGnB,uBACG,QAAQ,MAAM,EACd,YAAY,wBAAwB,EACpC,OAAO,4BAAU;AAMpB,UACG,QAAQ,cAAc,EACtB,YAAY,oCAAoC,EAChD,OAAO,oDAAsB;AAEhC,UACG,QAAQ,OAAO,EACf,YAAY,wBAAwB,EACpC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,uBAAuB,OAAO,EACrC,OAAO,gCAAgC,eAAe,EACtD,OAAO,kCAAkC,aAAa,EACtD,OAAO,wCAAwC,gBAAgB,EAC/D,OAAO,kBAAK;AAEf,UAAQ,MAAM,QAAQ,IAAI;AAE1B,SAAO;AACT;","names":[]}
@@ -22,9 +22,13 @@ __export(config_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(config_exports);
24
24
  var import_config = require("@intlayer/config");
25
- const getConfig = (_options) => {
25
+ const getConfig = (options) => {
26
26
  const config = (0, import_config.getConfiguration)();
27
- (0, import_config.logger)(config);
27
+ (0, import_config.logger)(JSON.stringify(config, null, 2), {
28
+ config: {
29
+ prefix: options?.logPrefix
30
+ }
31
+ });
28
32
  };
29
33
  // Annotate the CommonJS export names for ESM import in node:
30
34
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config.ts"],"sourcesContent":["import { getConfiguration, logger } from '@intlayer/config';\n\ntype ConfigOptions = {};\n\nexport const getConfig = (_options?: ConfigOptions) => {\n const config = getConfiguration();\n\n logger(config);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyC;AAIlC,MAAM,YAAY,CAAC,aAA6B;AACrD,QAAM,aAAS,gCAAiB;AAEhC,4BAAO,MAAM;AACf;","names":[]}
1
+ {"version":3,"sources":["../../src/config.ts"],"sourcesContent":["import { getConfiguration, logger } from '@intlayer/config';\n\ntype ConfigOptions = {\n logPrefix?: string;\n};\n\nexport const getConfig = (options?: ConfigOptions) => {\n const config = getConfiguration();\n\n logger(JSON.stringify(config, null, 2), {\n config: {\n prefix: options?.logPrefix,\n },\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyC;AAMlC,MAAM,YAAY,CAAC,YAA4B;AACpD,QAAM,aAAS,gCAAiB;AAEhC,4BAAO,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG;AAAA,IACtC,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -21,6 +21,7 @@ __reExport(index_exports, require('./pull.cjs'), module.exports);
21
21
  __reExport(index_exports, require('./push.cjs'), module.exports);
22
22
  __reExport(index_exports, require('./listContentDeclaration.cjs'), module.exports);
23
23
  __reExport(index_exports, require('./audit.cjs'), module.exports);
24
+ __reExport(index_exports, require('./pushConfig.cjs'), module.exports);
24
25
  // Annotate the CommonJS export names for ESM import in node:
25
26
  0 && (module.exports = {
26
27
  ...require('./cli.cjs'),
@@ -28,6 +29,7 @@ __reExport(index_exports, require('./audit.cjs'), module.exports);
28
29
  ...require('./pull.cjs'),
29
30
  ...require('./push.cjs'),
30
31
  ...require('./listContentDeclaration.cjs'),
31
- ...require('./audit.cjs')
32
+ ...require('./audit.cjs'),
33
+ ...require('./pushConfig.cjs')
32
34
  });
33
35
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './cli';\nexport * from './build';\nexport * from './pull';\nexport * from './push';\nexport * from './listContentDeclaration';\nexport * from './audit';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,kBAAd;AACA,0BAAc,oBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,mBAHd;AAIA,0BAAc,qCAJd;AAKA,0BAAc,oBALd;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './cli';\nexport * from './build';\nexport * from './pull';\nexport * from './push';\nexport * from './listContentDeclaration';\nexport * from './audit';\nexport * from './pushConfig';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,kBAAd;AACA,0BAAc,oBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,mBAHd;AAIA,0BAAc,qCAJd;AAKA,0BAAc,oBALd;AAMA,0BAAc,yBANd;","names":[]}
@@ -46,9 +46,13 @@ const getContentDeclaration = (options) => {
46
46
  );
47
47
  return contentDeclarationFilesPath;
48
48
  };
49
- const listContentDeclaration = (_options) => {
49
+ const listContentDeclaration = (options) => {
50
50
  const contentDeclarationFilesPath = getContentDeclaration();
51
- (0, import_config.logger)(`Content declaration files: ${contentDeclarationFilesPath}`);
51
+ (0, import_config.logger)(`Content declaration files: ${contentDeclarationFilesPath}`, {
52
+ config: {
53
+ prefix: options?.logPrefix
54
+ }
55
+ });
52
56
  };
53
57
  // Annotate the CommonJS export names for ESM import in node:
54
58
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/listContentDeclaration.ts"],"sourcesContent":["import { getConfiguration, logger } from '@intlayer/config';\nimport fg from 'fast-glob';\n\ntype GetContentDeclarationOptions = {\n exclude?: string[];\n};\n\nexport const getContentDeclaration = (\n options?: GetContentDeclarationOptions\n): string[] => {\n const {\n content: { watchedFilesPatternWithPath },\n } = getConfiguration();\n\n const contentDeclarationFilesPath: string[] = fg.sync(\n watchedFilesPatternWithPath,\n {\n ignore: options?.exclude,\n }\n );\n\n return contentDeclarationFilesPath;\n};\n\ntype ListContentDeclarationOptions = {};\n\nexport const listContentDeclaration = (\n _options: ListContentDeclarationOptions\n) => {\n const contentDeclarationFilesPath = getContentDeclaration();\n\n logger(`Content declaration files: ${contentDeclarationFilesPath}`);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyC;AACzC,uBAAe;AAMR,MAAM,wBAAwB,CACnC,YACa;AACb,QAAM;AAAA,IACJ,SAAS,EAAE,4BAA4B;AAAA,EACzC,QAAI,gCAAiB;AAErB,QAAM,8BAAwC,iBAAAA,QAAG;AAAA,IAC/C;AAAA,IACA;AAAA,MACE,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAIO,MAAM,yBAAyB,CACpC,aACG;AACH,QAAM,8BAA8B,sBAAsB;AAE1D,4BAAO,8BAA8B,2BAA2B,EAAE;AACpE;","names":["fg"]}
1
+ {"version":3,"sources":["../../src/listContentDeclaration.ts"],"sourcesContent":["import { getConfiguration, logger } from '@intlayer/config';\nimport fg from 'fast-glob';\n\ntype GetContentDeclarationOptions = {\n exclude?: string[];\n};\n\nexport const getContentDeclaration = (\n options?: GetContentDeclarationOptions\n): string[] => {\n const {\n content: { watchedFilesPatternWithPath },\n } = getConfiguration();\n\n const contentDeclarationFilesPath: string[] = fg.sync(\n watchedFilesPatternWithPath,\n {\n ignore: options?.exclude,\n }\n );\n\n return contentDeclarationFilesPath;\n};\n\ntype ListContentDeclarationOptions = {\n logPrefix?: string;\n};\n\nexport const listContentDeclaration = (\n options: ListContentDeclarationOptions\n) => {\n const contentDeclarationFilesPath = getContentDeclaration();\n\n logger(`Content declaration files: ${contentDeclarationFilesPath}`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyC;AACzC,uBAAe;AAMR,MAAM,wBAAwB,CACnC,YACa;AACb,QAAM;AAAA,IACJ,SAAS,EAAE,4BAA4B;AAAA,EACzC,QAAI,gCAAiB;AAErB,QAAM,8BAAwC,iBAAAA,QAAG;AAAA,IAC/C;AAAA,IACA;AAAA,MACE,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAMO,MAAM,yBAAyB,CACpC,YACG;AACH,QAAM,8BAA8B,sBAAsB;AAE1D,4BAAO,8BAA8B,2BAA2B,IAAI;AAAA,IAClE,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF,CAAC;AACH;","names":["fg"]}
package/dist/cjs/pull.cjs CHANGED
@@ -69,10 +69,19 @@ const pull = async (options) => {
69
69
  );
70
70
  }
71
71
  if (distantDictionariesKeys.length === 0) {
72
- (0, import_config.logger)("No dictionaries to fetch", { level: "error" });
72
+ (0, import_config.logger)("No dictionaries to fetch", {
73
+ level: "error",
74
+ config: {
75
+ prefix: options?.logPrefix
76
+ }
77
+ });
73
78
  return;
74
79
  }
75
- (0, import_config.logger)("Fetching dictionaries:");
80
+ (0, import_config.logger)("Fetching dictionaries:", {
81
+ config: {
82
+ prefix: options?.logPrefix
83
+ }
84
+ });
76
85
  const dictionariesStatuses = distantDictionariesKeys.map((dictionaryKey, index) => ({
77
86
  dictionaryKey,
78
87
  icon: getStatusIcon("pending"),
@@ -125,11 +134,21 @@ const pull = async (options) => {
125
134
  updateAllStatusLines(dictionariesStatuses);
126
135
  for (const statusObj of dictionariesStatuses) {
127
136
  if (statusObj.errorMessage) {
128
- (0, import_config.logger)(statusObj.errorMessage, { level: "error" });
137
+ (0, import_config.logger)(statusObj.errorMessage, {
138
+ level: "error",
139
+ config: {
140
+ prefix: options?.logPrefix
141
+ }
142
+ });
129
143
  }
130
144
  }
131
145
  } catch (error) {
132
- (0, import_config.logger)(error, { level: "error" });
146
+ (0, import_config.logger)(error, {
147
+ level: "error",
148
+ config: {
149
+ prefix: options?.logPrefix
150
+ }
151
+ });
133
152
  }
134
153
  };
135
154
  const getStatusIcon = (status) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport { writeContentDeclaration } from '@intlayer/editor/server';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status:\n | 'pending'\n | 'fetching'\n | 'up-to-date'\n | 'updated'\n | 'fetched'\n | 'unknown'\n | 'error'\n | 'imported'\n | 'reimported in JSON'\n | 'reimported in new location';\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 try {\n const config = getConfiguration();\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 headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\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 logger('No dictionaries to fetch', { level: 'error' });\n return;\n }\n\n logger('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 headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\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 logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\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":["pLimit"]}
1
+ {"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport { writeContentDeclaration } from '@intlayer/editor/server';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status:\n | 'pending'\n | 'fetching'\n | 'up-to-date'\n | 'updated'\n | 'fetched'\n | 'unknown'\n | 'error'\n | 'imported'\n | 'reimported in JSON'\n | 'reimported in new location';\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 try {\n const config = getConfiguration();\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 headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\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 logger('No dictionaries to fetch', {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n return;\n }\n\n logger('Fetching dictionaries:', {\n config: {\n prefix: options?.logPrefix,\n },\n });\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 headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\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 logger(statusObj.errorMessage, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n }\n } catch (error) {\n logger(error, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\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":["pLimit"]}
package/dist/cjs/push.cjs CHANGED
@@ -68,7 +68,12 @@ const push = async (options) => {
68
68
  `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(
69
69
  ", "
70
70
  )} and have been ignored.`,
71
- { level: "error" }
71
+ {
72
+ level: "error",
73
+ config: {
74
+ prefix: options?.logPrefix
75
+ }
76
+ }
72
77
  );
73
78
  }
74
79
  dictionaries = dictionaries.filter(
@@ -76,10 +81,19 @@ const push = async (options) => {
76
81
  );
77
82
  }
78
83
  if (dictionaries.length === 0) {
79
- (0, import_config.logger)("No local dictionaries found", { level: "error" });
84
+ (0, import_config.logger)("No local dictionaries found", {
85
+ level: "error",
86
+ config: {
87
+ prefix: options?.logPrefix
88
+ }
89
+ });
80
90
  return;
81
91
  }
82
- (0, import_config.logger)("Pushing dictionaries:");
92
+ (0, import_config.logger)("Pushing dictionaries:", {
93
+ config: {
94
+ prefix: options?.logPrefix
95
+ }
96
+ });
83
97
  const dictionariesStatuses = dictionaries.map(
84
98
  (dictionary, index) => ({
85
99
  dictionary,
@@ -133,7 +147,12 @@ const push = async (options) => {
133
147
  updateAllStatusLines(dictionariesStatuses);
134
148
  for (const statusObj of dictionariesStatuses) {
135
149
  if (statusObj.errorMessage) {
136
- (0, import_config.logger)(statusObj.errorMessage, { level: "error" });
150
+ (0, import_config.logger)(statusObj.errorMessage, {
151
+ level: "error",
152
+ config: {
153
+ prefix: options?.logPrefix
154
+ }
155
+ });
137
156
  }
138
157
  }
139
158
  const deleteOption = options?.deleteLocaleDictionary;
@@ -144,18 +163,23 @@ const push = async (options) => {
144
163
  );
145
164
  }
146
165
  if (deleteOption) {
147
- await deleteLocalDictionaries(successfullyPushedDictionaries);
166
+ await deleteLocalDictionaries(successfullyPushedDictionaries, options);
148
167
  } else if (keepOption) {
149
168
  } else {
150
169
  const answer = await askUser(
151
170
  "Do you want to delete the local dictionaries that were successfully pushed? (yes/no): "
152
171
  );
153
172
  if (answer.toLowerCase() === "yes" || answer.toLowerCase() === "y") {
154
- await deleteLocalDictionaries(successfullyPushedDictionaries);
173
+ await deleteLocalDictionaries(successfullyPushedDictionaries, options);
155
174
  }
156
175
  }
157
176
  } catch (error) {
158
- (0, import_config.logger)(error, { level: "error" });
177
+ (0, import_config.logger)(error, {
178
+ level: "error",
179
+ config: {
180
+ prefix: options?.logPrefix
181
+ }
182
+ });
159
183
  }
160
184
  };
161
185
  const askUser = (question) => {
@@ -170,14 +194,17 @@ const askUser = (question) => {
170
194
  });
171
195
  });
172
196
  };
173
- const deleteLocalDictionaries = async (dictionariesToDelete) => {
197
+ const deleteLocalDictionaries = async (dictionariesToDelete, options) => {
174
198
  const { baseDir } = (0, import_config.getConfiguration)().content;
175
199
  const filePathsSet = /* @__PURE__ */ new Set();
176
200
  for (const dictionary of dictionariesToDelete) {
177
201
  const { filePath } = dictionary;
178
202
  if (!filePath) {
179
203
  (0, import_config.logger)(`Dictionary ${dictionary.key} does not have a file path`, {
180
- level: "error"
204
+ level: "error",
205
+ config: {
206
+ prefix: options?.logPrefix
207
+ }
181
208
  });
182
209
  continue;
183
210
  }
@@ -189,15 +216,30 @@ const deleteLocalDictionaries = async (dictionariesToDelete) => {
189
216
  const stats = await fsPromises.lstat(filePath);
190
217
  if (stats.isFile()) {
191
218
  await fsPromises.unlink(filePath);
192
- (0, import_config.logger)(`Deleted file ${relativePath}`);
219
+ (0, import_config.logger)(`Deleted file ${relativePath}`, {
220
+ config: {
221
+ prefix: options?.logPrefix
222
+ }
223
+ });
193
224
  } else if (stats.isDirectory()) {
194
- (0, import_config.logger)(`Path is a directory ${relativePath}, skipping.`);
225
+ (0, import_config.logger)(`Path is a directory ${relativePath}, skipping.`, {
226
+ config: {
227
+ prefix: options?.logPrefix
228
+ }
229
+ });
195
230
  } else {
196
- (0, import_config.logger)(`Unknown file type for ${relativePath}, skipping.`);
231
+ (0, import_config.logger)(`Unknown file type for ${relativePath}, skipping.`, {
232
+ config: {
233
+ prefix: options?.logPrefix
234
+ }
235
+ });
197
236
  }
198
237
  } catch (err) {
199
238
  (0, import_config.logger)(`Error deleting ${relativePath}: ${err}`, {
200
- level: "error"
239
+ level: "error",
240
+ config: {
241
+ prefix: options?.logPrefix
242
+ }
201
243
  });
202
244
  }
203
245
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import * as fsPromises from 'fs/promises';\nimport { relative } from 'path';\nimport * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\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 GREY_DARK = '\\x1b[90m';\n\n/**\n * Get all locale dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n try {\n const config = getConfiguration();\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 const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n let dictionaries: Dictionary[] = Object.values(dictionariesRecord);\n const existingDictionariesKeys: string[] = Object.keys(dictionariesRecord);\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n logger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n { level: 'error' }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries!.includes(dictionary.key)\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n logger('No local dictionaries found', { level: 'error' });\n return;\n }\n\n logger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary, index) => ({\n dictionary,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n })\n );\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries(\n [statusObj.dictionary],\n {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }\n );\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries || [];\n const newDictionaries = pushResult.data?.newDictionaries || [];\n\n if (updatedDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n const pushPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n await Promise.all(pushPromises);\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 logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const answer = await askUser(\n 'Do you want to delete the local dictionaries that were successfully pushed? (yes/no): '\n );\n if (answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') {\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst askUser = (question: string): Promise<string> => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer: string) => {\n rl.close();\n resolve(answer);\n });\n });\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[]\n): Promise<void> => {\n const { baseDir } = getConfiguration().content;\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n logger(`Dictionary ${dictionary.key} does not have a file path`, {\n level: 'error',\n });\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n const relativePath = relative(baseDir, filePath);\n\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n logger(`Deleted file ${relativePath}`);\n } else if (stats.isDirectory()) {\n logger(`Path is a directory ${relativePath}, skipping.`);\n } else {\n logger(`Unknown file type for ${relativePath}, skipping.`);\n }\n } catch (err) {\n logger(`Error deleting ${relativePath}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n pushing: '', // Spinner handled separately\n modified: '✔',\n pushed: '✔',\n error: '✖',\n };\n return statusIcons[status] || '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'pushing') {\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 (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = GREEN;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${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 === 'pushing') {\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":["dictionariesRecord","pLimit"]}
1
+ {"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import * as fsPromises from 'fs/promises';\nimport { relative } from 'path';\nimport * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\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 GREY_DARK = '\\x1b[90m';\n\n/**\n * Get all locale dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n try {\n const config = getConfiguration();\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 const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n let dictionaries: Dictionary[] = Object.values(dictionariesRecord);\n const existingDictionariesKeys: string[] = Object.keys(dictionariesRecord);\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n logger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries!.includes(dictionary.key)\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n logger('No local dictionaries found', {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n return;\n }\n\n logger('Pushing dictionaries:', {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary, index) => ({\n dictionary,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n })\n );\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries(\n [statusObj.dictionary],\n {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }\n );\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries || [];\n const newDictionaries = pushResult.data?.newDictionaries || [];\n\n if (updatedDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n const pushPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n await Promise.all(pushPromises);\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 logger(statusObj.errorMessage, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries, options);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const answer = await askUser(\n 'Do you want to delete the local dictionaries that were successfully pushed? (yes/no): '\n );\n if (answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') {\n await deleteLocalDictionaries(successfullyPushedDictionaries, options);\n }\n }\n } catch (error) {\n logger(error, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n};\n\nconst askUser = (question: string): Promise<string> => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer: string) => {\n rl.close();\n resolve(answer);\n });\n });\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[],\n options?: PushOptions\n): Promise<void> => {\n const { baseDir } = getConfiguration().content;\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n logger(`Dictionary ${dictionary.key} does not have a file path`, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n const relativePath = relative(baseDir, filePath);\n\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n logger(`Deleted file ${relativePath}`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n } else if (stats.isDirectory()) {\n logger(`Path is a directory ${relativePath}, skipping.`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n } else {\n logger(`Unknown file type for ${relativePath}, skipping.`, {\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n } catch (err) {\n logger(`Error deleting ${relativePath}: ${err}`, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n pushing: '', // Spinner handled separately\n modified: '✔',\n pushed: '✔',\n error: '✖',\n };\n return statusIcons[status] || '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'pushing') {\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 (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = GREEN;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${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 === 'pushing') {\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":["dictionariesRecord","pLimit"]}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var pushConfig_exports = {};
20
+ __export(pushConfig_exports, {
21
+ pushConfig: () => pushConfig
22
+ });
23
+ module.exports = __toCommonJS(pushConfig_exports);
24
+ var import_api = require("@intlayer/api");
25
+ var import_config = require("@intlayer/config");
26
+ const pushConfig = async (options) => {
27
+ const config = (0, import_config.getConfiguration)();
28
+ const { clientId, clientSecret } = config.editor;
29
+ if (!clientId || !clientSecret) {
30
+ (0, import_config.logger)(
31
+ "Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.",
32
+ {
33
+ level: "error",
34
+ config: {
35
+ prefix: options?.logPrefix
36
+ }
37
+ }
38
+ );
39
+ return;
40
+ }
41
+ const intlayerAPI = (0, import_api.getIntlayerAPI)(void 0, config);
42
+ const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();
43
+ const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
44
+ const getDictionariesKeysResult = await intlayerAPI.project.pushProjectConfiguration(config, {
45
+ headers: { Authorization: `Bearer ${oAuth2AccessToken}` }
46
+ });
47
+ if (!getDictionariesKeysResult.data) {
48
+ throw new Error("Error pushing project configuration");
49
+ }
50
+ (0, import_config.logger)("Project configuration pushed successfully", {
51
+ config: {
52
+ prefix: options?.logPrefix
53
+ }
54
+ });
55
+ (0, import_config.logger)(JSON.stringify(getDictionariesKeysResult.data, null, 2), {
56
+ config: {
57
+ prefix: options?.logPrefix
58
+ }
59
+ });
60
+ };
61
+ // Annotate the CommonJS export names for ESM import in node:
62
+ 0 && (module.exports = {
63
+ pushConfig
64
+ });
65
+ //# sourceMappingURL=pushConfig.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pushConfig.ts"],"sourcesContent":["import { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\n\ntype PushOptions = {\n logPrefix?: string;\n environment?: string;\n};\n\nexport const pushConfig = async (options?: PushOptions) => {\n const config = getConfiguration();\n\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n logger(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.',\n {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n }\n );\n return;\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.project.pushProjectConfiguration(config, {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('Error pushing project configuration');\n }\n\n logger('Project configuration pushed successfully', {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n logger(JSON.stringify(getDictionariesKeysResult.data, null, 2), {\n config: {\n prefix: options?.logPrefix,\n },\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA+B;AAC/B,oBAAyC;AAOlC,MAAM,aAAa,OAAO,YAA0B;AACzD,QAAM,aAAS,gCAAiB;AAEhC,QAAM,EAAE,UAAU,aAAa,IAAI,OAAO;AAE1C,MAAI,CAAC,YAAY,CAAC,cAAc;AAC9B;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,QAAQ;AAAA,UACN,QAAQ,SAAS;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,QAAM,kBAAc,2BAAe,QAAW,MAAM;AAEpD,QAAM,oBAAoB,MAAM,YAAY,KAAK,qBAAqB;AAEtE,QAAM,oBAAoB,kBAAkB,MAAM;AAGlD,QAAM,4BACJ,MAAM,YAAY,QAAQ,yBAAyB,QAAQ;AAAA,IACzD,SAAS,EAAE,eAAe,UAAU,iBAAiB,GAAG;AAAA,EAC1D,CAAC;AAEH,MAAI,CAAC,0BAA0B,MAAM;AACnC,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAEA,4BAAO,6CAA6C;AAAA,IAClD,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF,CAAC;AAED,4BAAO,KAAK,UAAU,0BAA0B,MAAM,MAAM,CAAC,GAAG;AAAA,IAC9D,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -9,7 +9,11 @@ const auditFile = async (filePath, options) => {
9
9
  try {
10
10
  const { defaultLocale, locales } = getConfiguration().internationalization;
11
11
  const relativePath = relative(projectPath, filePath);
12
- logger(`Auditing file: ${relativePath}`);
12
+ logger(`Auditing file: ${relativePath}`, {
13
+ config: {
14
+ prefix: options?.logPrefix
15
+ }
16
+ });
13
17
  const fileContent = readFileSync(filePath, "utf-8");
14
18
  const auditFileResult = await intlayerAPI.ai.auditContentDeclaration(
15
19
  {
@@ -29,10 +33,23 @@ const auditFile = async (filePath, options) => {
29
33
  throw new Error("Audit failed");
30
34
  }
31
35
  writeFileSync(filePath, auditFileResult.data.fileContent);
32
- logger(`File ${relativePath} updated`);
33
- logger(`${auditFileResult.data.tokenUsed} tokens used in the request`);
36
+ logger(`File ${relativePath} updated`, {
37
+ config: {
38
+ prefix: options?.logPrefix
39
+ }
40
+ });
41
+ logger(`${auditFileResult.data.tokenUsed} tokens used in the request`, {
42
+ config: {
43
+ prefix: options?.logPrefix
44
+ }
45
+ });
34
46
  } catch (error) {
35
- logger(error, { level: "error" });
47
+ logger(error, {
48
+ level: "error",
49
+ config: {
50
+ prefix: options?.logPrefix
51
+ }
52
+ });
36
53
  }
37
54
  };
38
55
  const getAbsolutePath = (filePath) => {