@intlayer/cli 5.8.1 → 6.0.0-canary.1

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 (134) hide show
  1. package/dist/cjs/IntlayerEventListener.cjs +241 -0
  2. package/dist/cjs/IntlayerEventListener.cjs.map +1 -0
  3. package/dist/cjs/cli.cjs +29 -7
  4. package/dist/cjs/cli.cjs.map +1 -1
  5. package/dist/cjs/config.cjs +5 -1
  6. package/dist/cjs/config.cjs.map +1 -1
  7. package/dist/cjs/fill/autoFill.cjs +105 -0
  8. package/dist/cjs/fill/autoFill.cjs.map +1 -0
  9. package/dist/cjs/fill/formatAutoFillData.cjs +108 -0
  10. package/dist/cjs/fill/formatAutoFillData.cjs.map +1 -0
  11. package/dist/cjs/fill/formatAutoFilledFilePath.cjs +46 -0
  12. package/dist/cjs/fill/formatAutoFilledFilePath.cjs.map +1 -0
  13. package/dist/cjs/fill/getTargetDictionary.cjs +86 -0
  14. package/dist/cjs/fill/getTargetDictionary.cjs.map +1 -0
  15. package/dist/cjs/fill/index.cjs +257 -0
  16. package/dist/cjs/fill/index.cjs.map +1 -0
  17. package/dist/cjs/index.cjs +4 -2
  18. package/dist/cjs/index.cjs.map +1 -1
  19. package/dist/cjs/listContentDeclaration.cjs +37 -19
  20. package/dist/cjs/listContentDeclaration.cjs.map +1 -1
  21. package/dist/cjs/liveSync.cjs +254 -0
  22. package/dist/cjs/liveSync.cjs.map +1 -0
  23. package/dist/cjs/pull.cjs +119 -117
  24. package/dist/cjs/pull.cjs.map +1 -1
  25. package/dist/cjs/pullLog.cjs +146 -0
  26. package/dist/cjs/pullLog.cjs.map +1 -0
  27. package/dist/cjs/push.cjs +74 -88
  28. package/dist/cjs/push.cjs.map +1 -1
  29. package/dist/cjs/pushConfig.cjs +10 -25
  30. package/dist/cjs/pushConfig.cjs.map +1 -1
  31. package/dist/cjs/pushLog.cjs +130 -0
  32. package/dist/cjs/pushLog.cjs.map +1 -0
  33. package/dist/cjs/reviewDoc.cjs +45 -36
  34. package/dist/cjs/reviewDoc.cjs.map +1 -1
  35. package/dist/cjs/test/index.cjs +91 -0
  36. package/dist/cjs/test/index.cjs.map +1 -0
  37. package/dist/cjs/test/listMissingTranslations.cjs +73 -0
  38. package/dist/cjs/test/listMissingTranslations.cjs.map +1 -0
  39. package/dist/cjs/translateDoc.cjs +42 -34
  40. package/dist/cjs/translateDoc.cjs.map +1 -1
  41. package/dist/cjs/utils/checkAIAccess.cjs +5 -1
  42. package/dist/cjs/utils/checkAIAccess.cjs.map +1 -1
  43. package/dist/cjs/utils/chunkInference.cjs +7 -14
  44. package/dist/cjs/utils/chunkInference.cjs.map +1 -1
  45. package/dist/esm/IntlayerEventListener.mjs +207 -0
  46. package/dist/esm/IntlayerEventListener.mjs.map +1 -0
  47. package/dist/esm/cli.mjs +26 -4
  48. package/dist/esm/cli.mjs.map +1 -1
  49. package/dist/esm/config.mjs +5 -1
  50. package/dist/esm/config.mjs.map +1 -1
  51. package/dist/esm/fill/autoFill.mjs +92 -0
  52. package/dist/esm/fill/autoFill.mjs.map +1 -0
  53. package/dist/esm/fill/formatAutoFillData.mjs +84 -0
  54. package/dist/esm/fill/formatAutoFillData.mjs.map +1 -0
  55. package/dist/esm/fill/formatAutoFilledFilePath.mjs +22 -0
  56. package/dist/esm/fill/formatAutoFilledFilePath.mjs.map +1 -0
  57. package/dist/esm/fill/getTargetDictionary.mjs +51 -0
  58. package/dist/esm/fill/getTargetDictionary.mjs.map +1 -0
  59. package/dist/esm/fill/index.mjs +240 -0
  60. package/dist/esm/fill/index.mjs.map +1 -0
  61. package/dist/esm/index.mjs +2 -1
  62. package/dist/esm/index.mjs.map +1 -1
  63. package/dist/esm/listContentDeclaration.mjs +38 -17
  64. package/dist/esm/listContentDeclaration.mjs.map +1 -1
  65. package/dist/esm/liveSync.mjs +220 -0
  66. package/dist/esm/liveSync.mjs.map +1 -0
  67. package/dist/esm/pull.mjs +123 -108
  68. package/dist/esm/pull.mjs.map +1 -1
  69. package/dist/esm/pullLog.mjs +127 -0
  70. package/dist/esm/pullLog.mjs.map +1 -0
  71. package/dist/esm/push.mjs +81 -90
  72. package/dist/esm/push.mjs.map +1 -1
  73. package/dist/esm/pushConfig.mjs +11 -26
  74. package/dist/esm/pushConfig.mjs.map +1 -1
  75. package/dist/esm/pushLog.mjs +111 -0
  76. package/dist/esm/pushLog.mjs.map +1 -0
  77. package/dist/esm/reviewDoc.mjs +55 -38
  78. package/dist/esm/reviewDoc.mjs.map +1 -1
  79. package/dist/esm/test/index.mjs +74 -0
  80. package/dist/esm/test/index.mjs.map +1 -0
  81. package/dist/esm/test/listMissingTranslations.mjs +41 -0
  82. package/dist/esm/test/listMissingTranslations.mjs.map +1 -0
  83. package/dist/esm/translateDoc.mjs +52 -37
  84. package/dist/esm/translateDoc.mjs.map +1 -1
  85. package/dist/esm/utils/checkAIAccess.mjs +5 -1
  86. package/dist/esm/utils/checkAIAccess.mjs.map +1 -1
  87. package/dist/esm/utils/chunkInference.mjs +14 -16
  88. package/dist/esm/utils/chunkInference.mjs.map +1 -1
  89. package/dist/types/IntlayerEventListener.d.ts +85 -0
  90. package/dist/types/IntlayerEventListener.d.ts.map +1 -0
  91. package/dist/types/cli.d.ts.map +1 -1
  92. package/dist/types/config.d.ts.map +1 -1
  93. package/dist/types/fill/autoFill.d.ts +4 -0
  94. package/dist/types/fill/autoFill.d.ts.map +1 -0
  95. package/dist/types/fill/formatAutoFillData.d.ts +9 -0
  96. package/dist/types/fill/formatAutoFillData.d.ts.map +1 -0
  97. package/dist/types/fill/formatAutoFilledFilePath.d.ts +3 -0
  98. package/dist/types/fill/formatAutoFilledFilePath.d.ts.map +1 -0
  99. package/dist/types/fill/getTargetDictionary.d.ts +4 -0
  100. package/dist/types/fill/getTargetDictionary.d.ts.map +1 -0
  101. package/dist/types/{fill.d.ts → fill/index.d.ts} +2 -5
  102. package/dist/types/fill/index.d.ts.map +1 -0
  103. package/dist/types/index.d.ts +1 -0
  104. package/dist/types/index.d.ts.map +1 -1
  105. package/dist/types/listContentDeclaration.d.ts +4 -5
  106. package/dist/types/listContentDeclaration.d.ts.map +1 -1
  107. package/dist/types/liveSync.d.ts +6 -0
  108. package/dist/types/liveSync.d.ts.map +1 -0
  109. package/dist/types/pull.d.ts.map +1 -1
  110. package/dist/types/pullLog.d.ts +24 -0
  111. package/dist/types/pullLog.d.ts.map +1 -0
  112. package/dist/types/push.d.ts +1 -1
  113. package/dist/types/push.d.ts.map +1 -1
  114. package/dist/types/pushConfig.d.ts +0 -1
  115. package/dist/types/pushConfig.d.ts.map +1 -1
  116. package/dist/types/pushLog.d.ts +23 -0
  117. package/dist/types/pushLog.d.ts.map +1 -0
  118. package/dist/types/reviewDoc.d.ts +1 -1
  119. package/dist/types/reviewDoc.d.ts.map +1 -1
  120. package/dist/types/test/index.d.ts +8 -0
  121. package/dist/types/test/index.d.ts.map +1 -0
  122. package/dist/types/test/listMissingTranslations.d.ts +12 -0
  123. package/dist/types/test/listMissingTranslations.d.ts.map +1 -0
  124. package/dist/types/translateDoc.d.ts +1 -1
  125. package/dist/types/translateDoc.d.ts.map +1 -1
  126. package/dist/types/utils/checkAIAccess.d.ts.map +1 -1
  127. package/dist/types/utils/chunkInference.d.ts +2 -1
  128. package/dist/types/utils/chunkInference.d.ts.map +1 -1
  129. package/package.json +19 -15
  130. package/dist/cjs/fill.cjs +0 -405
  131. package/dist/cjs/fill.cjs.map +0 -1
  132. package/dist/esm/fill.mjs +0 -385
  133. package/dist/esm/fill.mjs.map +0 -1
  134. package/dist/types/fill.d.ts.map +0 -1
@@ -0,0 +1,127 @@
1
+ import {
2
+ ANSIColors,
3
+ colorize,
4
+ getConfiguration,
5
+ spinnerFrames
6
+ } from "@intlayer/config";
7
+ class PullLogger {
8
+ statuses = [];
9
+ spinnerTimer = null;
10
+ spinnerIndex = 0;
11
+ renderedLines = 0;
12
+ spinnerFrames = spinnerFrames;
13
+ isFinished = false;
14
+ prefix;
15
+ lastRenderedState = "";
16
+ constructor() {
17
+ const configuration = getConfiguration();
18
+ this.prefix = configuration.log.prefix;
19
+ }
20
+ update(newStatuses) {
21
+ if (this.isFinished) return;
22
+ for (const status of newStatuses) {
23
+ const index = this.statuses.findIndex(
24
+ (s) => s.dictionaryKey === status.dictionaryKey
25
+ );
26
+ if (index >= 0) {
27
+ this.statuses[index] = status;
28
+ } else {
29
+ this.statuses.push(status);
30
+ }
31
+ }
32
+ this.startSpinner();
33
+ this.render();
34
+ }
35
+ finish() {
36
+ this.isFinished = true;
37
+ this.stopSpinner();
38
+ this.render();
39
+ }
40
+ startSpinner() {
41
+ if (this.spinnerTimer || this.isFinished) return;
42
+ this.spinnerTimer = setInterval(() => {
43
+ this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
44
+ this.render();
45
+ }, 100);
46
+ }
47
+ stopSpinner() {
48
+ if (!this.spinnerTimer) return;
49
+ clearInterval(this.spinnerTimer);
50
+ this.spinnerTimer = null;
51
+ }
52
+ render() {
53
+ const { total, done, success, errors } = this.computeProgress();
54
+ const frame = this.spinnerFrames[this.spinnerIndex];
55
+ const lines = [];
56
+ const isDone = done === total;
57
+ const progressLabel = `dictionaries: ${done}/${total}`;
58
+ const details = [];
59
+ if (success > 0) details.push(`ok: ${success}`);
60
+ if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));
61
+ const suffix = details.length > 0 ? ` (${details.join(", ")})` : "";
62
+ if (isDone) {
63
+ lines.push(
64
+ `${this.prefix} ${colorize("\u2714", ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`
65
+ );
66
+ } else {
67
+ lines.push(
68
+ `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`
69
+ );
70
+ }
71
+ const currentState = lines.join("\n");
72
+ if (currentState === this.lastRenderedState) {
73
+ return;
74
+ }
75
+ this.lastRenderedState = currentState;
76
+ if (this.renderedLines > 0) {
77
+ process.stdout.write(`\x1B[${this.renderedLines}F`);
78
+ }
79
+ const totalLinesToClear = Math.max(this.renderedLines, lines.length);
80
+ for (let i = 0; i < totalLinesToClear; i++) {
81
+ process.stdout.write("\x1B[2K");
82
+ const line = lines[i];
83
+ if (line !== void 0) {
84
+ process.stdout.write(line);
85
+ }
86
+ process.stdout.write("\n");
87
+ }
88
+ this.renderedLines = lines.length;
89
+ }
90
+ computeProgress() {
91
+ const keys = new Set(this.statuses.map((s) => s.dictionaryKey));
92
+ const doneSet = /* @__PURE__ */ new Set([
93
+ "fetched",
94
+ "imported",
95
+ "updated",
96
+ "up-to-date",
97
+ "reimported in JSON",
98
+ "new content file",
99
+ "error"
100
+ ]);
101
+ const successesSet = /* @__PURE__ */ new Set([
102
+ "fetched",
103
+ "imported",
104
+ "updated",
105
+ "up-to-date",
106
+ "reimported in JSON",
107
+ "new content file"
108
+ ]);
109
+ const done = this.statuses.filter(
110
+ (s) => doneSet.has(s.status)
111
+ ).length;
112
+ const success = this.statuses.filter(
113
+ (s) => successesSet.has(s.status)
114
+ ).length;
115
+ const errors = this.statuses.filter((s) => s.status === "error").length;
116
+ return {
117
+ total: keys.size,
118
+ done,
119
+ success,
120
+ errors
121
+ };
122
+ }
123
+ }
124
+ export {
125
+ PullLogger
126
+ };
127
+ //# sourceMappingURL=pullLog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pullLog.ts"],"sourcesContent":["import { type DictionaryStatus } from '@intlayer/chokidar';\nimport {\n ANSIColors,\n colorize,\n getConfiguration,\n spinnerFrames,\n} from '@intlayer/config';\n\nexport type PullStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching';\n errorMessage?: string;\n};\n\nexport class PullLogger {\n private statuses: PullStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n\n constructor() {\n const configuration = getConfiguration();\n this.prefix = configuration.log.prefix;\n }\n\n update(newStatuses: PullStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) => s.dictionaryKey === status.dictionaryKey\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n private render() {\n const { total, done, success, errors } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const lines: string[] = [];\n\n const isDone = done === total;\n const progressLabel = `dictionaries: ${done}/${total}`;\n const details: string[] = [];\n if (success > 0) details.push(`ok: ${success}`);\n if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));\n\n const suffix = details.length > 0 ? ` (${details.join(', ')})` : '';\n\n if (isDone) {\n lines.push(\n `${this.prefix} ${colorize('✔', ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`\n );\n }\n\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const keys = new Set(this.statuses.map((s) => s.dictionaryKey));\n\n const doneSet = new Set<DictionaryStatus | 'error'>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n 'error',\n ] as const);\n\n const successesSet = new Set<DictionaryStatus>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n ] as const);\n\n const done = this.statuses.filter((s) =>\n doneSet.has(s.status as any)\n ).length;\n const success = this.statuses.filter((s) =>\n successesSet.has(s.status as any)\n ).length;\n const errors = this.statuses.filter((s) => s.status === 'error').length;\n\n return {\n total: keys.size,\n done,\n success,\n errors,\n } as const;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/esm/push.mjs CHANGED
@@ -1,24 +1,25 @@
1
- import { getDictionaryAPI, getOAuthAPI } from "@intlayer/api";
2
- import { listGitFiles } from "@intlayer/chokidar";
1
+ import { getIntlayerAPIProxy } from "@intlayer/api";
3
2
  import {
3
+ formatPath,
4
+ listGitFiles,
5
+ parallelize
6
+ } from "@intlayer/chokidar";
7
+ import {
8
+ ANSIColors,
4
9
  getAppLogger,
5
10
  getConfiguration
6
11
  } from "@intlayer/config";
7
12
  import dictionariesRecord from "@intlayer/dictionaries-entry";
8
13
  import * as fsPromises from "fs/promises";
9
- import pLimit from "p-limit";
10
- import { relative } from "path";
11
14
  import * as readline from "readline";
12
- const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
13
- const RESET = "\x1B[0m";
14
- const GREEN = "\x1B[32m";
15
- const RED = "\x1B[31m";
16
- const BLUE = "\x1B[34m";
17
- const GREY = "\x1B[90m";
18
- const GREY_DARK = "\x1B[90m";
15
+ import { PushLogger } from "./pushLog.mjs";
19
16
  const push = async (options) => {
20
17
  const config = getConfiguration(options?.configOptions);
21
- const appLogger = getAppLogger(config);
18
+ const appLogger = getAppLogger(config, {
19
+ config: {
20
+ prefix: ""
21
+ }
22
+ });
22
23
  const { clientId, clientSecret } = config.editor;
23
24
  try {
24
25
  if (!clientId || !clientSecret) {
@@ -26,9 +27,7 @@ const push = async (options) => {
26
27
  "Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
27
28
  );
28
29
  }
29
- const intlayerAuthAPI = getOAuthAPI(config);
30
- const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();
31
- const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
30
+ const intlayerAPI = getIntlayerAPIProxy(void 0, config);
32
31
  let dictionaries = Object.values(dictionariesRecord);
33
32
  const existingDictionariesKeys = Object.keys(dictionariesRecord);
34
33
  if (options?.dictionaries) {
@@ -60,41 +59,42 @@ const push = async (options) => {
60
59
  }
61
60
  appLogger("Pushing dictionaries:", {});
62
61
  const dictionariesStatuses = dictionaries.map(
63
- (dictionary, index) => ({
62
+ (dictionary) => ({
64
63
  dictionary,
65
- icon: getStatusIcon("pending"),
66
- status: "pending",
67
- index,
68
- spinnerFrameIndex: 0
64
+ status: "pending"
69
65
  })
70
66
  );
71
- for (const statusObj of dictionariesStatuses) {
72
- process.stdout.write(getStatusLine(statusObj) + "\n");
73
- }
67
+ const logger = new PushLogger();
68
+ logger.update(
69
+ dictionariesStatuses.map((s) => ({
70
+ dictionaryKey: s.dictionary.key,
71
+ status: "pending"
72
+ }))
73
+ );
74
74
  const successfullyPushedDictionaries = [];
75
- const spinnerTimer = setInterval(() => {
76
- updateAllStatusLines(dictionariesStatuses);
77
- }, 100);
78
75
  const processDictionary = async (statusObj) => {
79
76
  statusObj.status = "pushing";
77
+ logger.update([
78
+ { dictionaryKey: statusObj.dictionary.key, status: "pushing" }
79
+ ]);
80
80
  try {
81
- const intlayerDictionaryAPI = getDictionaryAPI(void 0, config);
82
- const pushResult = await intlayerDictionaryAPI.pushDictionaries(
83
- [statusObj.dictionary],
84
- {
85
- headers: {
86
- Authorization: `Bearer ${oAuth2AccessToken}`
87
- }
88
- }
89
- );
81
+ const pushResult = await intlayerAPI.dictionary.pushDictionaries([
82
+ statusObj.dictionary
83
+ ]);
90
84
  const updatedDictionaries = pushResult.data?.updatedDictionaries || [];
91
85
  const newDictionaries = pushResult.data?.newDictionaries || [];
92
86
  if (updatedDictionaries.includes(statusObj.dictionary.key)) {
93
87
  statusObj.status = "modified";
94
88
  successfullyPushedDictionaries.push(statusObj.dictionary);
89
+ logger.update([
90
+ { dictionaryKey: statusObj.dictionary.key, status: "modified" }
91
+ ]);
95
92
  } else if (newDictionaries.includes(statusObj.dictionary.key)) {
96
93
  statusObj.status = "pushed";
97
94
  successfullyPushedDictionaries.push(statusObj.dictionary);
95
+ logger.update([
96
+ { dictionaryKey: statusObj.dictionary.key, status: "pushed" }
97
+ ]);
98
98
  } else {
99
99
  statusObj.status = "unknown";
100
100
  }
@@ -102,15 +102,42 @@ const push = async (options) => {
102
102
  statusObj.status = "error";
103
103
  statusObj.error = error;
104
104
  statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;
105
+ logger.update([
106
+ { dictionaryKey: statusObj.dictionary.key, status: "error" }
107
+ ]);
105
108
  }
106
109
  };
107
- const limit = pLimit(5);
108
- const pushPromises = dictionariesStatuses.map(
109
- (statusObj) => limit(() => processDictionary(statusObj))
110
- );
111
- await Promise.all(pushPromises);
112
- clearInterval(spinnerTimer);
113
- updateAllStatusLines(dictionariesStatuses);
110
+ await parallelize(dictionariesStatuses, processDictionary, 5);
111
+ logger.finish();
112
+ const iconFor = (status) => {
113
+ switch (status) {
114
+ case "pushed":
115
+ case "modified":
116
+ return "\u2714";
117
+ case "error":
118
+ return "\u2716";
119
+ default:
120
+ return "\u23F2";
121
+ }
122
+ };
123
+ const colorFor = (status) => {
124
+ switch (status) {
125
+ case "pushed":
126
+ case "modified":
127
+ return ANSIColors.GREEN;
128
+ case "error":
129
+ return ANSIColors.RED;
130
+ default:
131
+ return ANSIColors.BLUE;
132
+ }
133
+ };
134
+ for (const s of dictionariesStatuses) {
135
+ const icon = iconFor(s.status);
136
+ const color = colorFor(s.status);
137
+ appLogger(
138
+ ` - ${s.dictionary.key} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`
139
+ );
140
+ }
114
141
  for (const statusObj of dictionariesStatuses) {
115
142
  if (statusObj.errorMessage) {
116
143
  appLogger(statusObj.errorMessage, {
@@ -156,8 +183,11 @@ const askUser = (question) => {
156
183
  };
157
184
  const deleteLocalDictionaries = async (dictionariesToDelete, options) => {
158
185
  const config = getConfiguration(options?.configOptions);
159
- const appLogger = getAppLogger(config);
160
- const { baseDir } = config.content;
186
+ const appLogger = getAppLogger(config, {
187
+ config: {
188
+ prefix: ""
189
+ }
190
+ });
161
191
  const filePathsSet = /* @__PURE__ */ new Set();
162
192
  for (const dictionary of dictionariesToDelete) {
163
193
  const { filePath } = dictionary;
@@ -170,65 +200,26 @@ const deleteLocalDictionaries = async (dictionariesToDelete, options) => {
170
200
  filePathsSet.add(filePath);
171
201
  }
172
202
  for (const filePath of filePathsSet) {
173
- const relativePath = relative(baseDir, filePath);
174
203
  try {
175
204
  const stats = await fsPromises.lstat(filePath);
176
205
  if (stats.isFile()) {
177
206
  await fsPromises.unlink(filePath);
178
- appLogger(`Deleted file ${relativePath}`, {});
207
+ appLogger(`Deleted file ${formatPath(filePath)}`, {});
179
208
  } else if (stats.isDirectory()) {
180
- appLogger(`Path is a directory ${relativePath}, skipping.`, {});
209
+ appLogger(`Path is a directory ${formatPath(filePath)}, skipping.`, {});
181
210
  } else {
182
- appLogger(`Unknown file type for ${relativePath}, skipping.`, {});
211
+ appLogger(
212
+ `Unknown file type for ${formatPath(filePath)}, skipping.`,
213
+ {}
214
+ );
183
215
  }
184
216
  } catch (err) {
185
- appLogger(`Error deleting ${relativePath}: ${err}`, {
217
+ appLogger(`Error deleting ${formatPath(filePath)}: ${err}`, {
186
218
  level: "error"
187
219
  });
188
220
  }
189
221
  }
190
222
  };
191
- const getStatusIcon = (status) => {
192
- const statusIcons = {
193
- pending: "\u23F2",
194
- pushing: "",
195
- // Spinner handled separately
196
- modified: "\u2714",
197
- pushed: "\u2714",
198
- error: "\u2716"
199
- };
200
- return statusIcons[status] || "";
201
- };
202
- const getStatusLine = (statusObj) => {
203
- let icon = getStatusIcon(statusObj.status);
204
- let colorStart = "";
205
- let colorEnd = "";
206
- if (statusObj.status === "pushing") {
207
- icon = spinnerFrames[statusObj.spinnerFrameIndex % spinnerFrames.length];
208
- colorStart = BLUE;
209
- colorEnd = RESET;
210
- } else if (statusObj.status === "error") {
211
- colorStart = RED;
212
- colorEnd = RESET;
213
- } else if (statusObj.status === "pushed" || statusObj.status === "modified") {
214
- colorStart = GREEN;
215
- colorEnd = RESET;
216
- } else {
217
- colorStart = GREY;
218
- colorEnd = RESET;
219
- }
220
- return `- ${statusObj.dictionary.key} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;
221
- };
222
- const updateAllStatusLines = (dictionariesStatuses) => {
223
- readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);
224
- for (const statusObj of dictionariesStatuses) {
225
- readline.clearLine(process.stdout, 0);
226
- if (statusObj.status === "pushing") {
227
- statusObj.spinnerFrameIndex = (statusObj.spinnerFrameIndex + 1) % spinnerFrames.length;
228
- }
229
- process.stdout.write(getStatusLine(statusObj) + "\n");
230
- }
231
- };
232
223
  export {
233
224
  push
234
225
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import { getDictionaryAPI, getOAuthAPI } from '@intlayer/api';\nimport { listGitFiles, ListGitFilesOptions } from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n} from '@intlayer/config';\nimport type { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport * as fsPromises from 'fs/promises';\nimport pLimit from 'p-limit';\nimport { relative } from 'path';\nimport * as readline from 'readline';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\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 const config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config);\n const { clientId, clientSecret } = config.editor;\n try {\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 intlayerAuthAPI = getOAuthAPI(config);\n const oAuth2TokenResult = await intlayerAuthAPI.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 appLogger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n {\n level: 'error',\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 if (options?.gitOptions) {\n const gitFiles = await listGitFiles(options.gitOptions);\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n appLogger('No local dictionaries found', {\n level: 'error',\n });\n return;\n }\n\n appLogger('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 intlayerDictionaryAPI = getDictionaryAPI(undefined, config);\n const pushResult = await intlayerDictionaryAPI.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 appLogger(statusObj.errorMessage, {\n level: 'error',\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 appLogger(error, {\n level: 'error',\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 config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config);\n const { baseDir } = config.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 appLogger(`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 appLogger(`Deleted file ${relativePath}`, {});\n } else if (stats.isDirectory()) {\n appLogger(`Path is a directory ${relativePath}, skipping.`, {});\n } else {\n appLogger(`Unknown file type for ${relativePath}, skipping.`, {});\n }\n } catch (err) {\n appLogger(`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 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":[]}
1
+ {"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n formatPath,\n listGitFiles,\n ListGitFilesOptions,\n parallelize,\n} from '@intlayer/chokidar';\nimport {\n ANSIColors,\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n} from '@intlayer/config';\nimport type { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport * as fsPromises from 'fs/promises';\nimport * as readline from 'readline';\nimport { PushLogger, type PushStatus } from './pushLog';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Get all local dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n const config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config, {\n config: {\n prefix: '',\n },\n });\n const { clientId, clientSecret } = config.editor;\n try {\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 = getIntlayerAPIProxy(undefined, config);\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 appLogger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n {\n level: 'error',\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 if (options?.gitOptions) {\n const gitFiles = await listGitFiles(options.gitOptions);\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n appLogger('No local dictionaries found', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Pushing dictionaries:', {});\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary) => ({\n dictionary,\n status: 'pending',\n })\n );\n\n // Initialize aggregated logger similar to loadDictionaries\n const logger = new PushLogger();\n logger.update(\n dictionariesStatuses.map<PushStatus>((s) => ({\n dictionaryKey: s.dictionary.key,\n status: 'pending',\n }))\n );\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'pushing' },\n ]);\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries([\n statusObj.dictionary,\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 logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'modified' },\n ]);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'pushed' },\n ]);\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 logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit (reuse parallelize)\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Print per-dictionary summary similar to loadDictionaries\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'pushed':\n case 'modified':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'pushed':\n case 'modified':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionary.key} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\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\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 appLogger(error, {\n level: 'error',\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 config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config, {\n config: {\n prefix: '',\n },\n });\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 appLogger(`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 try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n appLogger(`Deleted file ${formatPath(filePath)}`, {});\n } else if (stats.isDirectory()) {\n appLogger(`Path is a directory ${formatPath(filePath)}, skipping.`, {});\n } else {\n appLogger(\n `Unknown file type for ${formatPath(filePath)}, skipping.`,\n {}\n );\n }\n } catch (err) {\n appLogger(`Error deleting ${formatPath(filePath)}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n\n// Legacy per-line spinner output removed in favor of aggregated PushLogger\n"],"mappings":"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","names":[]}
@@ -1,47 +1,32 @@
1
- import { getIntlayerAPI } from "@intlayer/api";
1
+ import { getIntlayerAPIProxy } from "@intlayer/api";
2
2
  import {
3
3
  getAppLogger,
4
4
  getConfiguration
5
5
  } from "@intlayer/config";
6
6
  const pushConfig = async (options) => {
7
7
  const config = getConfiguration(options?.configOptions);
8
- const appLogger = getAppLogger(config);
8
+ const appLogger = getAppLogger(config, {
9
+ config: {
10
+ prefix: ""
11
+ }
12
+ });
9
13
  const { clientId, clientSecret } = config.editor;
10
14
  if (!clientId || !clientSecret) {
11
15
  appLogger(
12
16
  "Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.",
13
17
  {
14
- level: "error",
15
- config: {
16
- prefix: options?.logPrefix
17
- }
18
+ level: "error"
18
19
  }
19
20
  );
20
21
  return;
21
22
  }
22
- const intlayerAPI = getIntlayerAPI(void 0, config);
23
- const oAuth2TokenResult = await intlayerAPI.oAuth.getOAuth2AccessToken();
24
- const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
25
- const getDictionariesKeysResult = await intlayerAPI.project.pushProjectConfiguration(config, {
26
- ...oAuth2AccessToken && {
27
- headers: {
28
- Authorization: `Bearer ${oAuth2AccessToken}`
29
- }
30
- }
31
- });
23
+ const intlayerAPI = getIntlayerAPIProxy(void 0, config);
24
+ const getDictionariesKeysResult = await intlayerAPI.project.pushProjectConfiguration(config);
32
25
  if (!getDictionariesKeysResult.data) {
33
26
  throw new Error("Error pushing project configuration");
34
27
  }
35
- appLogger("Project configuration pushed successfully", {
36
- config: {
37
- prefix: options?.logPrefix
38
- }
39
- });
40
- appLogger(JSON.stringify(getDictionariesKeysResult.data, null, 2), {
41
- config: {
42
- prefix: options?.logPrefix
43
- }
44
- });
28
+ appLogger("Project configuration pushed successfully");
29
+ appLogger(JSON.stringify(getDictionariesKeysResult.data, null, 2));
45
30
  };
46
31
  export {
47
32
  pushConfig
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pushConfig.ts"],"sourcesContent":["import { getIntlayerAPI } from '@intlayer/api';\nimport {\n getAppLogger,\n getConfiguration,\n type GetConfigurationOptions,\n} from '@intlayer/config';\n\ntype PushOptions = {\n logPrefix?: string;\n configOptions?: GetConfigurationOptions;\n};\n\nexport const pushConfig = async (options?: PushOptions) => {\n const config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config);\n\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n appLogger(\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.oAuth.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 ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('Error pushing project configuration');\n }\n\n appLogger('Project configuration pushed successfully', {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n appLogger(JSON.stringify(getDictionariesKeysResult.data, null, 2), {\n config: {\n prefix: options?.logPrefix,\n },\n });\n};\n"],"mappings":"AAAA,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAOA,MAAM,aAAa,OAAO,YAA0B;AACzD,QAAM,SAAS,iBAAiB,SAAS,aAAa;AACtD,QAAM,YAAY,aAAa,MAAM;AAErC,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,cAAc,eAAe,QAAW,MAAM;AAEpD,QAAM,oBAAoB,MAAM,YAAY,MAAM,qBAAqB;AAEvE,QAAM,oBAAoB,kBAAkB,MAAM;AAGlD,QAAM,4BACJ,MAAM,YAAY,QAAQ,yBAAyB,QAAQ;AAAA,IACzD,GAAI,qBAAqB;AAAA,MACvB,SAAS;AAAA,QACP,eAAe,UAAU,iBAAiB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAC;AAEH,MAAI,CAAC,0BAA0B,MAAM;AACnC,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAEA,YAAU,6CAA6C;AAAA,IACrD,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF,CAAC;AAED,YAAU,KAAK,UAAU,0BAA0B,MAAM,MAAM,CAAC,GAAG;AAAA,IACjE,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../src/pushConfig.ts"],"sourcesContent":["import { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n getAppLogger,\n getConfiguration,\n type GetConfigurationOptions,\n} from '@intlayer/config';\n\ntype PushOptions = {\n configOptions?: GetConfigurationOptions;\n};\n\nexport const pushConfig = async (options?: PushOptions) => {\n const config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config, {\n config: {\n prefix: '',\n },\n });\n\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n appLogger(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.',\n {\n level: 'error',\n }\n );\n return;\n }\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n // Push the project configuration\n const getDictionariesKeysResult =\n await intlayerAPI.project.pushProjectConfiguration(config);\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('Error pushing project configuration');\n }\n\n appLogger('Project configuration pushed successfully');\n\n appLogger(JSON.stringify(getDictionariesKeysResult.data, null, 2));\n};\n"],"mappings":"AAAA,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAMA,MAAM,aAAa,OAAO,YAA0B;AACzD,QAAM,SAAS,iBAAiB,SAAS,aAAa;AACtD,QAAM,YAAY,aAAa,QAAQ;AAAA,IACrC,QAAQ;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,QAAM,EAAE,UAAU,aAAa,IAAI,OAAO;AAE1C,MAAI,CAAC,YAAY,CAAC,cAAc;AAC9B;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,MACT;AAAA,IACF;AACA;AAAA,EACF;AAEA,QAAM,cAAc,oBAAoB,QAAW,MAAM;AAGzD,QAAM,4BACJ,MAAM,YAAY,QAAQ,yBAAyB,MAAM;AAE3D,MAAI,CAAC,0BAA0B,MAAM;AACnC,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAEA,YAAU,2CAA2C;AAErD,YAAU,KAAK,UAAU,0BAA0B,MAAM,MAAM,CAAC,CAAC;AACnE;","names":[]}
@@ -0,0 +1,111 @@
1
+ import {
2
+ ANSIColors,
3
+ colorize,
4
+ getConfiguration,
5
+ spinnerFrames
6
+ } from "@intlayer/config";
7
+ class PushLogger {
8
+ statuses = [];
9
+ spinnerTimer = null;
10
+ spinnerIndex = 0;
11
+ renderedLines = 0;
12
+ spinnerFrames = spinnerFrames;
13
+ isFinished = false;
14
+ prefix;
15
+ lastRenderedState = "";
16
+ constructor() {
17
+ const configuration = getConfiguration();
18
+ this.prefix = configuration.log.prefix;
19
+ }
20
+ update(newStatuses) {
21
+ if (this.isFinished) return;
22
+ for (const status of newStatuses) {
23
+ const index = this.statuses.findIndex(
24
+ (s) => s.dictionaryKey === status.dictionaryKey
25
+ );
26
+ if (index >= 0) {
27
+ this.statuses[index] = status;
28
+ } else {
29
+ this.statuses.push(status);
30
+ }
31
+ }
32
+ this.startSpinner();
33
+ this.render();
34
+ }
35
+ finish() {
36
+ this.isFinished = true;
37
+ this.stopSpinner();
38
+ this.render();
39
+ }
40
+ startSpinner() {
41
+ if (this.spinnerTimer || this.isFinished) return;
42
+ this.spinnerTimer = setInterval(() => {
43
+ this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
44
+ this.render();
45
+ }, 100);
46
+ }
47
+ stopSpinner() {
48
+ if (!this.spinnerTimer) return;
49
+ clearInterval(this.spinnerTimer);
50
+ this.spinnerTimer = null;
51
+ }
52
+ render() {
53
+ const { total, done, pushed, modified, errors } = this.computeProgress();
54
+ const frame = this.spinnerFrames[this.spinnerIndex];
55
+ const lines = [];
56
+ const isDone = done === total;
57
+ const progressLabel = `dictionaries: ${done}/${total}`;
58
+ const details = [];
59
+ if (pushed > 0) details.push(`new: ${pushed}`);
60
+ if (modified > 0) details.push(`modified: ${modified}`);
61
+ if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));
62
+ const suffix = details.length > 0 ? ` (${details.join(", ")})` : "";
63
+ if (isDone) {
64
+ lines.push(
65
+ `${this.prefix} ${colorize("\u2714", ANSIColors.GREEN)} pushed ${progressLabel}${suffix}`
66
+ );
67
+ } else {
68
+ lines.push(
69
+ `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} pushing ${progressLabel}${suffix}`
70
+ );
71
+ }
72
+ const currentState = lines.join("\n");
73
+ if (currentState === this.lastRenderedState) {
74
+ return;
75
+ }
76
+ this.lastRenderedState = currentState;
77
+ if (this.renderedLines > 0) {
78
+ process.stdout.write(`\x1B[${this.renderedLines}F`);
79
+ }
80
+ const totalLinesToClear = Math.max(this.renderedLines, lines.length);
81
+ for (let i = 0; i < totalLinesToClear; i++) {
82
+ process.stdout.write("\x1B[2K");
83
+ const line = lines[i];
84
+ if (line !== void 0) {
85
+ process.stdout.write(line);
86
+ }
87
+ process.stdout.write("\n");
88
+ }
89
+ this.renderedLines = lines.length;
90
+ }
91
+ computeProgress() {
92
+ const keys = new Set(this.statuses.map((s) => s.dictionaryKey));
93
+ const pushed = this.statuses.filter((s) => s.status === "pushed").length;
94
+ const modified = this.statuses.filter(
95
+ (s) => s.status === "modified"
96
+ ).length;
97
+ const errors = this.statuses.filter((s) => s.status === "error").length;
98
+ const done = pushed + modified + errors;
99
+ return {
100
+ total: keys.size,
101
+ done,
102
+ pushed,
103
+ modified,
104
+ errors
105
+ };
106
+ }
107
+ }
108
+ export {
109
+ PushLogger
110
+ };
111
+ //# sourceMappingURL=pushLog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pushLog.ts"],"sourcesContent":["import {\n ANSIColors,\n colorize,\n getConfiguration,\n spinnerFrames,\n} from '@intlayer/config';\n\nexport type PushStatus = {\n dictionaryKey: string;\n status: 'pending' | 'pushing' | 'pushed' | 'modified' | 'error';\n errorMessage?: string;\n};\n\nexport class PushLogger {\n private statuses: PushStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n\n constructor() {\n const configuration = getConfiguration();\n this.prefix = configuration.log.prefix;\n }\n\n update(newStatuses: PushStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) => s.dictionaryKey === status.dictionaryKey\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n private render() {\n const { total, done, pushed, modified, errors } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const lines: string[] = [];\n\n const isDone = done === total;\n\n const progressLabel = `dictionaries: ${done}/${total}`;\n const details: string[] = [];\n if (pushed > 0) details.push(`new: ${pushed}`);\n if (modified > 0) details.push(`modified: ${modified}`);\n if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));\n\n const suffix = details.length > 0 ? ` (${details.join(', ')})` : '';\n\n if (isDone) {\n lines.push(\n `${this.prefix} ${colorize('✔', ANSIColors.GREEN)} pushed ${progressLabel}${suffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} pushing ${progressLabel}${suffix}`\n );\n }\n\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const keys = new Set(this.statuses.map((s) => s.dictionaryKey));\n\n const pushed = this.statuses.filter((s) => s.status === 'pushed').length;\n const modified = this.statuses.filter(\n (s) => s.status === 'modified'\n ).length;\n const errors = this.statuses.filter((s) => s.status === 'error').length;\n const done = pushed + modified + errors;\n\n return {\n total: keys.size,\n done,\n pushed,\n modified,\n errors,\n } as const;\n }\n}\n"],"mappings":"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","names":[]}