@intlayer/cli 6.0.0-canary.0 → 6.0.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/IntlayerEventListener.cjs +3 -2
- package/dist/cjs/IntlayerEventListener.cjs.map +1 -1
- package/dist/cjs/pull.cjs +114 -108
- package/dist/cjs/pull.cjs.map +1 -1
- package/dist/cjs/pullLog.cjs +146 -0
- package/dist/cjs/pullLog.cjs.map +1 -0
- package/dist/cjs/push.cjs +57 -72
- package/dist/cjs/push.cjs.map +1 -1
- package/dist/cjs/pushConfig.cjs +2 -10
- package/dist/cjs/pushConfig.cjs.map +1 -1
- package/dist/cjs/pushLog.cjs +130 -0
- package/dist/cjs/pushLog.cjs.map +1 -0
- package/dist/cjs/reviewDoc.cjs +2 -10
- package/dist/cjs/reviewDoc.cjs.map +1 -1
- package/dist/cjs/translateDoc.cjs +2 -10
- package/dist/cjs/translateDoc.cjs.map +1 -1
- package/dist/cjs/utils/chunkInference.cjs +7 -14
- package/dist/cjs/utils/chunkInference.cjs.map +1 -1
- package/dist/esm/IntlayerEventListener.mjs +4 -3
- package/dist/esm/IntlayerEventListener.mjs.map +1 -1
- package/dist/esm/pull.mjs +118 -101
- package/dist/esm/pull.mjs.map +1 -1
- package/dist/esm/pullLog.mjs +127 -0
- package/dist/esm/pullLog.mjs.map +1 -0
- package/dist/esm/push.mjs +61 -76
- package/dist/esm/push.mjs.map +1 -1
- package/dist/esm/pushConfig.mjs +3 -11
- package/dist/esm/pushConfig.mjs.map +1 -1
- package/dist/esm/pushLog.mjs +111 -0
- package/dist/esm/pushLog.mjs.map +1 -0
- package/dist/esm/reviewDoc.mjs +2 -10
- package/dist/esm/reviewDoc.mjs.map +1 -1
- package/dist/esm/translateDoc.mjs +2 -10
- package/dist/esm/translateDoc.mjs.map +1 -1
- package/dist/esm/utils/chunkInference.mjs +14 -16
- package/dist/esm/utils/chunkInference.mjs.map +1 -1
- package/dist/types/IntlayerEventListener.d.ts.map +1 -1
- package/dist/types/pull.d.ts.map +1 -1
- package/dist/types/pullLog.d.ts +24 -0
- package/dist/types/pullLog.d.ts.map +1 -0
- package/dist/types/push.d.ts.map +1 -1
- package/dist/types/pushConfig.d.ts.map +1 -1
- package/dist/types/pushLog.d.ts +23 -0
- package/dist/types/pushLog.d.ts.map +1 -0
- package/dist/types/reviewDoc.d.ts +1 -1
- package/dist/types/reviewDoc.d.ts.map +1 -1
- package/dist/types/translateDoc.d.ts +1 -1
- package/dist/types/translateDoc.d.ts.map +1 -1
- package/dist/types/utils/chunkInference.d.ts +2 -1
- package/dist/types/utils/chunkInference.d.ts.map +1 -1
- package/package.json +15 -13
|
@@ -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,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getIntlayerAPIProxy } from "@intlayer/api";
|
|
2
2
|
import {
|
|
3
3
|
formatPath,
|
|
4
|
-
listGitFiles
|
|
4
|
+
listGitFiles,
|
|
5
|
+
parallelize
|
|
5
6
|
} from "@intlayer/chokidar";
|
|
6
7
|
import {
|
|
7
8
|
ANSIColors,
|
|
8
9
|
getAppLogger,
|
|
9
|
-
getConfiguration
|
|
10
|
-
spinnerFrames
|
|
10
|
+
getConfiguration
|
|
11
11
|
} from "@intlayer/config";
|
|
12
12
|
import dictionariesRecord from "@intlayer/dictionaries-entry";
|
|
13
13
|
import * as fsPromises from "fs/promises";
|
|
14
|
-
import pLimit from "p-limit";
|
|
15
14
|
import * as readline from "readline";
|
|
15
|
+
import { PushLogger } from "./pushLog.mjs";
|
|
16
16
|
const push = async (options) => {
|
|
17
17
|
const config = getConfiguration(options?.configOptions);
|
|
18
18
|
const appLogger = getAppLogger(config, {
|
|
@@ -27,9 +27,7 @@ const push = async (options) => {
|
|
|
27
27
|
"Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
|
-
const
|
|
31
|
-
const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();
|
|
32
|
-
const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
30
|
+
const intlayerAPI = getIntlayerAPIProxy(void 0, config);
|
|
33
31
|
let dictionaries = Object.values(dictionariesRecord);
|
|
34
32
|
const existingDictionariesKeys = Object.keys(dictionariesRecord);
|
|
35
33
|
if (options?.dictionaries) {
|
|
@@ -61,41 +59,42 @@ const push = async (options) => {
|
|
|
61
59
|
}
|
|
62
60
|
appLogger("Pushing dictionaries:", {});
|
|
63
61
|
const dictionariesStatuses = dictionaries.map(
|
|
64
|
-
(dictionary
|
|
62
|
+
(dictionary) => ({
|
|
65
63
|
dictionary,
|
|
66
|
-
|
|
67
|
-
status: "pending",
|
|
68
|
-
index,
|
|
69
|
-
spinnerFrameIndex: 0
|
|
64
|
+
status: "pending"
|
|
70
65
|
})
|
|
71
66
|
);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
const logger = new PushLogger();
|
|
68
|
+
logger.update(
|
|
69
|
+
dictionariesStatuses.map((s) => ({
|
|
70
|
+
dictionaryKey: s.dictionary.key,
|
|
71
|
+
status: "pending"
|
|
72
|
+
}))
|
|
73
|
+
);
|
|
75
74
|
const successfullyPushedDictionaries = [];
|
|
76
|
-
const spinnerTimer = setInterval(() => {
|
|
77
|
-
updateAllStatusLines(dictionariesStatuses);
|
|
78
|
-
}, 100);
|
|
79
75
|
const processDictionary = async (statusObj) => {
|
|
80
76
|
statusObj.status = "pushing";
|
|
77
|
+
logger.update([
|
|
78
|
+
{ dictionaryKey: statusObj.dictionary.key, status: "pushing" }
|
|
79
|
+
]);
|
|
81
80
|
try {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
headers: {
|
|
87
|
-
Authorization: `Bearer ${oAuth2AccessToken}`
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
);
|
|
81
|
+
const pushResult = await intlayerAPI.dictionary.pushDictionaries([
|
|
82
|
+
statusObj.dictionary
|
|
83
|
+
]);
|
|
91
84
|
const updatedDictionaries = pushResult.data?.updatedDictionaries || [];
|
|
92
85
|
const newDictionaries = pushResult.data?.newDictionaries || [];
|
|
93
86
|
if (updatedDictionaries.includes(statusObj.dictionary.key)) {
|
|
94
87
|
statusObj.status = "modified";
|
|
95
88
|
successfullyPushedDictionaries.push(statusObj.dictionary);
|
|
89
|
+
logger.update([
|
|
90
|
+
{ dictionaryKey: statusObj.dictionary.key, status: "modified" }
|
|
91
|
+
]);
|
|
96
92
|
} else if (newDictionaries.includes(statusObj.dictionary.key)) {
|
|
97
93
|
statusObj.status = "pushed";
|
|
98
94
|
successfullyPushedDictionaries.push(statusObj.dictionary);
|
|
95
|
+
logger.update([
|
|
96
|
+
{ dictionaryKey: statusObj.dictionary.key, status: "pushed" }
|
|
97
|
+
]);
|
|
99
98
|
} else {
|
|
100
99
|
statusObj.status = "unknown";
|
|
101
100
|
}
|
|
@@ -103,15 +102,42 @@ const push = async (options) => {
|
|
|
103
102
|
statusObj.status = "error";
|
|
104
103
|
statusObj.error = error;
|
|
105
104
|
statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;
|
|
105
|
+
logger.update([
|
|
106
|
+
{ dictionaryKey: statusObj.dictionary.key, status: "error" }
|
|
107
|
+
]);
|
|
106
108
|
}
|
|
107
109
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
+
}
|
|
115
141
|
for (const statusObj of dictionariesStatuses) {
|
|
116
142
|
if (statusObj.errorMessage) {
|
|
117
143
|
appLogger(statusObj.errorMessage, {
|
|
@@ -194,47 +220,6 @@ const deleteLocalDictionaries = async (dictionariesToDelete, options) => {
|
|
|
194
220
|
}
|
|
195
221
|
}
|
|
196
222
|
};
|
|
197
|
-
const getStatusIcon = (status) => {
|
|
198
|
-
const statusIcons = {
|
|
199
|
-
pending: "\u23F2",
|
|
200
|
-
pushing: "",
|
|
201
|
-
// Spinner handled separately
|
|
202
|
-
modified: "\u2714",
|
|
203
|
-
pushed: "\u2714",
|
|
204
|
-
error: "\u2716"
|
|
205
|
-
};
|
|
206
|
-
return statusIcons[status] || "";
|
|
207
|
-
};
|
|
208
|
-
const getStatusLine = (statusObj) => {
|
|
209
|
-
let icon = getStatusIcon(statusObj.status);
|
|
210
|
-
let colorStart = "";
|
|
211
|
-
let colorEnd = "";
|
|
212
|
-
if (statusObj.status === "pushing") {
|
|
213
|
-
icon = spinnerFrames[statusObj.spinnerFrameIndex % spinnerFrames.length];
|
|
214
|
-
colorStart = ANSIColors.BLUE;
|
|
215
|
-
colorEnd = ANSIColors.RESET;
|
|
216
|
-
} else if (statusObj.status === "error") {
|
|
217
|
-
colorStart = ANSIColors.RED;
|
|
218
|
-
colorEnd = ANSIColors.RESET;
|
|
219
|
-
} else if (statusObj.status === "pushed" || statusObj.status === "modified") {
|
|
220
|
-
colorStart = ANSIColors.GREEN;
|
|
221
|
-
colorEnd = ANSIColors.RESET;
|
|
222
|
-
} else {
|
|
223
|
-
colorStart = ANSIColors.GREY;
|
|
224
|
-
colorEnd = ANSIColors.RESET;
|
|
225
|
-
}
|
|
226
|
-
return `- ${statusObj.dictionary.key} ${ANSIColors.GREY_DARK}[${colorStart}${icon}${statusObj.status}${ANSIColors.GREY_DARK}]${colorEnd}`;
|
|
227
|
-
};
|
|
228
|
-
const updateAllStatusLines = (dictionariesStatuses) => {
|
|
229
|
-
readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);
|
|
230
|
-
for (const statusObj of dictionariesStatuses) {
|
|
231
|
-
readline.clearLine(process.stdout, 0);
|
|
232
|
-
if (statusObj.status === "pushing") {
|
|
233
|
-
statusObj.spinnerFrameIndex = (statusObj.spinnerFrameIndex + 1) % spinnerFrames.length;
|
|
234
|
-
}
|
|
235
|
-
process.stdout.write(getStatusLine(statusObj) + "\n");
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
223
|
export {
|
|
239
224
|
push
|
|
240
225
|
};
|
package/dist/esm/push.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import { getDictionaryAPI, getOAuthAPI } from '@intlayer/api';\nimport {\n formatPath,\n listGitFiles,\n ListGitFilesOptions,\n} from '@intlayer/chokidar';\nimport {\n ANSIColors,\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n spinnerFrames,\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 * 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\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 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 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\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 = ANSIColors.BLUE;\n colorEnd = ANSIColors.RESET;\n } else if (statusObj.status === 'error') {\n colorStart = ANSIColors.RED;\n colorEnd = ANSIColors.RESET;\n } else if (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = ANSIColors.GREEN;\n colorEnd = ANSIColors.RESET;\n } else {\n colorStart = ANSIColors.GREY;\n colorEnd = ANSIColors.RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${ANSIColors.GREY_DARK}[${colorStart}${icon}${statusObj.status}${ANSIColors.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":[]}
|
package/dist/esm/pushConfig.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getIntlayerAPIProxy } from "@intlayer/api";
|
|
2
2
|
import {
|
|
3
3
|
getAppLogger,
|
|
4
4
|
getConfiguration
|
|
@@ -20,16 +20,8 @@ const pushConfig = async (options) => {
|
|
|
20
20
|
);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
-
const intlayerAPI =
|
|
24
|
-
const
|
|
25
|
-
const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
26
|
-
const getDictionariesKeysResult = await intlayerAPI.project.pushProjectConfiguration(config, {
|
|
27
|
-
...oAuth2AccessToken && {
|
|
28
|
-
headers: {
|
|
29
|
-
Authorization: `Bearer ${oAuth2AccessToken}`
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
});
|
|
23
|
+
const intlayerAPI = getIntlayerAPIProxy(void 0, config);
|
|
24
|
+
const getDictionariesKeysResult = await intlayerAPI.project.pushProjectConfiguration(config);
|
|
33
25
|
if (!getDictionariesKeysResult.data) {
|
|
34
26
|
throw new Error("Error pushing project configuration");
|
|
35
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pushConfig.ts"],"sourcesContent":["import {
|
|
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":[]}
|
package/dist/esm/reviewDoc.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getOAuthAPI } from "@intlayer/api";
|
|
2
1
|
import {
|
|
3
2
|
formatLocale,
|
|
4
3
|
formatPath,
|
|
@@ -30,7 +29,7 @@ import { getChunk } from "./utils/getChunk.mjs";
|
|
|
30
29
|
import { getOutputFilePath } from "./utils/getOutputFilePath.mjs";
|
|
31
30
|
const isESModule = typeof import.meta.url === "string";
|
|
32
31
|
const dir = isESModule ? dirname(fileURLToPath(import.meta.url)) : __dirname;
|
|
33
|
-
const reviewFile = async (baseFilePath, outputFilePath, locale, baseLocale, aiOptions, configOptions,
|
|
32
|
+
const reviewFile = async (baseFilePath, outputFilePath, locale, baseLocale, aiOptions, configOptions, customInstructions, changedLines) => {
|
|
34
33
|
try {
|
|
35
34
|
const configuration = getConfiguration(configOptions);
|
|
36
35
|
const appLogger = getAppLogger(configuration, {
|
|
@@ -95,7 +94,7 @@ const reviewFile = async (baseFilePath, outputFilePath, locale, baseLocale, aiOp
|
|
|
95
94
|
{ role: "user", content: baseChunkContext.content }
|
|
96
95
|
],
|
|
97
96
|
aiOptions,
|
|
98
|
-
|
|
97
|
+
configOptions
|
|
99
98
|
);
|
|
100
99
|
appLogger(
|
|
101
100
|
`${prefix}${colorizeNumber(result.tokenUsed)} tokens used - Chunk ${colorizeNumber(i + 1)} of ${colorizeNumber(baseChunks.length)}`
|
|
@@ -163,12 +162,6 @@ const reviewDoc = async ({
|
|
|
163
162
|
}
|
|
164
163
|
}
|
|
165
164
|
checkAIAccess(configuration, aiOptions);
|
|
166
|
-
let oAuth2AccessToken;
|
|
167
|
-
if (configuration.editor.clientId) {
|
|
168
|
-
const intlayerAuthAPI = getOAuthAPI(configuration);
|
|
169
|
-
const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();
|
|
170
|
-
oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
171
|
-
}
|
|
172
165
|
appLogger(`Base locale is ${formatLocale(baseLocale)}`);
|
|
173
166
|
appLogger(
|
|
174
167
|
`Reviewing ${colorizeNumber(locales.length)} locales: [ ${formatLocale(locales)} ]`
|
|
@@ -207,7 +200,6 @@ const reviewDoc = async ({
|
|
|
207
200
|
baseLocale,
|
|
208
201
|
aiOptions,
|
|
209
202
|
configOptions,
|
|
210
|
-
oAuth2AccessToken,
|
|
211
203
|
customInstructions,
|
|
212
204
|
changedLines
|
|
213
205
|
);
|