@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.
- package/dist/cjs/IntlayerEventListener.cjs +241 -0
- package/dist/cjs/IntlayerEventListener.cjs.map +1 -0
- package/dist/cjs/cli.cjs +29 -7
- package/dist/cjs/cli.cjs.map +1 -1
- package/dist/cjs/config.cjs +5 -1
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/fill/autoFill.cjs +105 -0
- package/dist/cjs/fill/autoFill.cjs.map +1 -0
- package/dist/cjs/fill/formatAutoFillData.cjs +108 -0
- package/dist/cjs/fill/formatAutoFillData.cjs.map +1 -0
- package/dist/cjs/fill/formatAutoFilledFilePath.cjs +46 -0
- package/dist/cjs/fill/formatAutoFilledFilePath.cjs.map +1 -0
- package/dist/cjs/fill/getTargetDictionary.cjs +86 -0
- package/dist/cjs/fill/getTargetDictionary.cjs.map +1 -0
- package/dist/cjs/fill/index.cjs +257 -0
- package/dist/cjs/fill/index.cjs.map +1 -0
- package/dist/cjs/index.cjs +4 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/listContentDeclaration.cjs +37 -19
- package/dist/cjs/listContentDeclaration.cjs.map +1 -1
- package/dist/cjs/liveSync.cjs +254 -0
- package/dist/cjs/liveSync.cjs.map +1 -0
- package/dist/cjs/pull.cjs +119 -117
- 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 +74 -88
- package/dist/cjs/push.cjs.map +1 -1
- package/dist/cjs/pushConfig.cjs +10 -25
- 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 +45 -36
- package/dist/cjs/reviewDoc.cjs.map +1 -1
- package/dist/cjs/test/index.cjs +91 -0
- package/dist/cjs/test/index.cjs.map +1 -0
- package/dist/cjs/test/listMissingTranslations.cjs +73 -0
- package/dist/cjs/test/listMissingTranslations.cjs.map +1 -0
- package/dist/cjs/translateDoc.cjs +42 -34
- package/dist/cjs/translateDoc.cjs.map +1 -1
- package/dist/cjs/utils/checkAIAccess.cjs +5 -1
- package/dist/cjs/utils/checkAIAccess.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 +207 -0
- package/dist/esm/IntlayerEventListener.mjs.map +1 -0
- package/dist/esm/cli.mjs +26 -4
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/config.mjs +5 -1
- package/dist/esm/config.mjs.map +1 -1
- package/dist/esm/fill/autoFill.mjs +92 -0
- package/dist/esm/fill/autoFill.mjs.map +1 -0
- package/dist/esm/fill/formatAutoFillData.mjs +84 -0
- package/dist/esm/fill/formatAutoFillData.mjs.map +1 -0
- package/dist/esm/fill/formatAutoFilledFilePath.mjs +22 -0
- package/dist/esm/fill/formatAutoFilledFilePath.mjs.map +1 -0
- package/dist/esm/fill/getTargetDictionary.mjs +51 -0
- package/dist/esm/fill/getTargetDictionary.mjs.map +1 -0
- package/dist/esm/fill/index.mjs +240 -0
- package/dist/esm/fill/index.mjs.map +1 -0
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/listContentDeclaration.mjs +38 -17
- package/dist/esm/listContentDeclaration.mjs.map +1 -1
- package/dist/esm/liveSync.mjs +220 -0
- package/dist/esm/liveSync.mjs.map +1 -0
- package/dist/esm/pull.mjs +123 -108
- 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 +81 -90
- package/dist/esm/push.mjs.map +1 -1
- package/dist/esm/pushConfig.mjs +11 -26
- 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 +55 -38
- package/dist/esm/reviewDoc.mjs.map +1 -1
- package/dist/esm/test/index.mjs +74 -0
- package/dist/esm/test/index.mjs.map +1 -0
- package/dist/esm/test/listMissingTranslations.mjs +41 -0
- package/dist/esm/test/listMissingTranslations.mjs.map +1 -0
- package/dist/esm/translateDoc.mjs +52 -37
- package/dist/esm/translateDoc.mjs.map +1 -1
- package/dist/esm/utils/checkAIAccess.mjs +5 -1
- package/dist/esm/utils/checkAIAccess.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 +85 -0
- package/dist/types/IntlayerEventListener.d.ts.map +1 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/fill/autoFill.d.ts +4 -0
- package/dist/types/fill/autoFill.d.ts.map +1 -0
- package/dist/types/fill/formatAutoFillData.d.ts +9 -0
- package/dist/types/fill/formatAutoFillData.d.ts.map +1 -0
- package/dist/types/fill/formatAutoFilledFilePath.d.ts +3 -0
- package/dist/types/fill/formatAutoFilledFilePath.d.ts.map +1 -0
- package/dist/types/fill/getTargetDictionary.d.ts +4 -0
- package/dist/types/fill/getTargetDictionary.d.ts.map +1 -0
- package/dist/types/{fill.d.ts → fill/index.d.ts} +2 -5
- package/dist/types/fill/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/listContentDeclaration.d.ts +4 -5
- package/dist/types/listContentDeclaration.d.ts.map +1 -1
- package/dist/types/liveSync.d.ts +6 -0
- package/dist/types/liveSync.d.ts.map +1 -0
- 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 +1 -1
- package/dist/types/push.d.ts.map +1 -1
- package/dist/types/pushConfig.d.ts +0 -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/test/index.d.ts +8 -0
- package/dist/types/test/index.d.ts.map +1 -0
- package/dist/types/test/listMissingTranslations.d.ts +12 -0
- package/dist/types/test/listMissingTranslations.d.ts.map +1 -0
- package/dist/types/translateDoc.d.ts +1 -1
- package/dist/types/translateDoc.d.ts.map +1 -1
- package/dist/types/utils/checkAIAccess.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 +19 -15
- package/dist/cjs/fill.cjs +0 -405
- package/dist/cjs/fill.cjs.map +0 -1
- package/dist/esm/fill.mjs +0 -385
- package/dist/esm/fill.mjs.map +0 -1
- package/dist/types/fill.d.ts.map +0 -1
package/dist/cjs/pull.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
var pull_exports = {};
|
|
30
20
|
__export(pull_exports, {
|
|
@@ -34,18 +24,15 @@ module.exports = __toCommonJS(pull_exports);
|
|
|
34
24
|
var import_api = require("@intlayer/api");
|
|
35
25
|
var import_chokidar = require("@intlayer/chokidar");
|
|
36
26
|
var import_config = require("@intlayer/config");
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
const RESET = "\x1B[0m";
|
|
41
|
-
const GREEN = "\x1B[32m";
|
|
42
|
-
const RED = "\x1B[31m";
|
|
43
|
-
const BLUE = "\x1B[34m";
|
|
44
|
-
const GREY = "\x1B[90m";
|
|
45
|
-
const YELLOW = "\x1B[33m";
|
|
46
|
-
const GREY_DARK = "\x1B[90m";
|
|
27
|
+
var import_fs = require("fs");
|
|
28
|
+
var import_path = require("path");
|
|
29
|
+
var import_pullLog = require('./pullLog.cjs');
|
|
47
30
|
const pull = async (options) => {
|
|
48
|
-
const appLogger = (0, import_config.getAppLogger)(options?.configOptions?.override
|
|
31
|
+
const appLogger = (0, import_config.getAppLogger)(options?.configOptions?.override, {
|
|
32
|
+
config: {
|
|
33
|
+
prefix: ""
|
|
34
|
+
}
|
|
35
|
+
});
|
|
49
36
|
try {
|
|
50
37
|
const config = (0, import_config.getConfiguration)(options?.configOptions);
|
|
51
38
|
const { clientId, clientSecret } = config.editor;
|
|
@@ -54,86 +41,146 @@ const pull = async (options) => {
|
|
|
54
41
|
"Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
|
|
55
42
|
);
|
|
56
43
|
}
|
|
57
|
-
const intlayerAPI = (0, import_api.
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const getDictionariesKeysResult = await intlayerAPI.dictionary.getDictionariesKeys({
|
|
61
|
-
...oAuth2AccessToken && {
|
|
62
|
-
headers: {
|
|
63
|
-
Authorization: `Bearer ${oAuth2AccessToken}`
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
if (!getDictionariesKeysResult.data) {
|
|
44
|
+
const intlayerAPI = (0, import_api.getIntlayerAPIProxy)(void 0, config);
|
|
45
|
+
const getDictionariesUpdateTimestampResult = await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();
|
|
46
|
+
if (!getDictionariesUpdateTimestampResult.data) {
|
|
68
47
|
throw new Error("No distant dictionaries found");
|
|
69
48
|
}
|
|
70
|
-
let
|
|
49
|
+
let distantDictionariesUpdateTimeStamp = getDictionariesUpdateTimestampResult.data;
|
|
71
50
|
if (options?.dictionaries) {
|
|
72
|
-
|
|
73
|
-
(
|
|
51
|
+
distantDictionariesUpdateTimeStamp = Object.fromEntries(
|
|
52
|
+
Object.entries(distantDictionariesUpdateTimeStamp).filter(
|
|
53
|
+
([key]) => options.dictionaries.includes(key)
|
|
54
|
+
)
|
|
74
55
|
);
|
|
75
56
|
}
|
|
76
|
-
|
|
57
|
+
const remoteDictionariesPath = (0, import_path.join)(
|
|
58
|
+
config.content.mainDir,
|
|
59
|
+
"remote_dictionaries.cjs"
|
|
60
|
+
);
|
|
61
|
+
const remoteDictionariesRecord = (0, import_fs.existsSync)(
|
|
62
|
+
remoteDictionariesPath
|
|
63
|
+
) ? (0, import_config.ESMxCJSRequire)(remoteDictionariesPath) : {};
|
|
64
|
+
const entries = Object.entries(distantDictionariesUpdateTimeStamp);
|
|
65
|
+
const keysToFetch = entries.filter(([key, remoteUpdatedAt]) => {
|
|
66
|
+
if (!remoteUpdatedAt) return true;
|
|
67
|
+
const local = remoteDictionariesRecord[key];
|
|
68
|
+
if (!local) return true;
|
|
69
|
+
const localUpdatedAtRaw = local?.updatedAt;
|
|
70
|
+
const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
|
|
71
|
+
if (typeof localUpdatedAt !== "number") return true;
|
|
72
|
+
return remoteUpdatedAt > localUpdatedAt;
|
|
73
|
+
}).map(([key]) => key);
|
|
74
|
+
const cachedKeys = entries.filter(([key, remoteUpdatedAt]) => {
|
|
75
|
+
const local = remoteDictionariesRecord[key];
|
|
76
|
+
const localUpdatedAtRaw = local?.updatedAt;
|
|
77
|
+
const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
|
|
78
|
+
return typeof localUpdatedAt === "number" && typeof remoteUpdatedAt === "number" && localUpdatedAt >= remoteUpdatedAt;
|
|
79
|
+
}).map(([key]) => key);
|
|
80
|
+
if (entries.length === 0) {
|
|
77
81
|
appLogger("No dictionaries to fetch", {
|
|
78
82
|
level: "error"
|
|
79
83
|
});
|
|
80
84
|
return;
|
|
81
85
|
}
|
|
82
86
|
appLogger("Fetching dictionaries:");
|
|
83
|
-
const dictionariesStatuses =
|
|
84
|
-
dictionaryKey
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
const dictionariesStatuses = [
|
|
88
|
+
...cachedKeys.map((dictionaryKey) => ({
|
|
89
|
+
dictionaryKey,
|
|
90
|
+
status: "imported"
|
|
91
|
+
})),
|
|
92
|
+
...keysToFetch.map((dictionaryKey) => ({
|
|
93
|
+
dictionaryKey,
|
|
94
|
+
status: "pending"
|
|
95
|
+
}))
|
|
96
|
+
];
|
|
97
|
+
const logger = new import_pullLog.PullLogger();
|
|
98
|
+
logger.update(
|
|
99
|
+
dictionariesStatuses.map((s) => ({
|
|
100
|
+
dictionaryKey: s.dictionaryKey,
|
|
101
|
+
status: s.status
|
|
102
|
+
}))
|
|
103
|
+
);
|
|
97
104
|
const successfullyFetchedDictionaries = [];
|
|
98
105
|
const processDictionary = async (statusObj) => {
|
|
99
|
-
statusObj.status
|
|
106
|
+
const isCached = statusObj.status === "imported" || statusObj.status === "up-to-date";
|
|
107
|
+
if (!isCached) {
|
|
108
|
+
statusObj.status = "fetching";
|
|
109
|
+
logger.update([
|
|
110
|
+
{ dictionaryKey: statusObj.dictionaryKey, status: "fetching" }
|
|
111
|
+
]);
|
|
112
|
+
}
|
|
100
113
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
);
|
|
112
|
-
const distantDictionary = getDictionaryResult.data;
|
|
113
|
-
if (!distantDictionary) {
|
|
114
|
+
let sourceDictionary;
|
|
115
|
+
if (isCached) {
|
|
116
|
+
sourceDictionary = remoteDictionariesRecord[statusObj.dictionaryKey];
|
|
117
|
+
}
|
|
118
|
+
if (!sourceDictionary) {
|
|
119
|
+
const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);
|
|
120
|
+
sourceDictionary = getDictionaryResult.data;
|
|
121
|
+
}
|
|
122
|
+
if (!sourceDictionary) {
|
|
114
123
|
throw new Error(
|
|
115
124
|
`Dictionary ${statusObj.dictionaryKey} not found on remote`
|
|
116
125
|
);
|
|
117
126
|
}
|
|
118
127
|
const { status } = await (0, import_chokidar.writeContentDeclaration)(
|
|
119
|
-
|
|
128
|
+
sourceDictionary,
|
|
120
129
|
config,
|
|
121
130
|
options?.newDictionariesPath
|
|
122
131
|
);
|
|
123
132
|
statusObj.status = status;
|
|
124
|
-
|
|
133
|
+
logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);
|
|
134
|
+
successfullyFetchedDictionaries.push(sourceDictionary);
|
|
125
135
|
} catch (error) {
|
|
126
136
|
statusObj.status = "error";
|
|
127
137
|
statusObj.error = error;
|
|
128
138
|
statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;
|
|
139
|
+
logger.update([
|
|
140
|
+
{ dictionaryKey: statusObj.dictionaryKey, status: "error" }
|
|
141
|
+
]);
|
|
129
142
|
}
|
|
130
143
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
await (0, import_chokidar.parallelize)(dictionariesStatuses, processDictionary, 5);
|
|
145
|
+
logger.finish();
|
|
146
|
+
const iconFor = (status) => {
|
|
147
|
+
switch (status) {
|
|
148
|
+
case "fetched":
|
|
149
|
+
case "imported":
|
|
150
|
+
case "updated":
|
|
151
|
+
case "up-to-date":
|
|
152
|
+
case "reimported in JSON":
|
|
153
|
+
case "new content file":
|
|
154
|
+
return "\u2714";
|
|
155
|
+
case "error":
|
|
156
|
+
return "\u2716";
|
|
157
|
+
default:
|
|
158
|
+
return "\u23F2";
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const colorFor = (status) => {
|
|
162
|
+
switch (status) {
|
|
163
|
+
case "fetched":
|
|
164
|
+
case "imported":
|
|
165
|
+
case "updated":
|
|
166
|
+
case "up-to-date":
|
|
167
|
+
return import_config.ANSIColors.GREEN;
|
|
168
|
+
case "reimported in JSON":
|
|
169
|
+
case "new content file":
|
|
170
|
+
return import_config.ANSIColors.YELLOW;
|
|
171
|
+
case "error":
|
|
172
|
+
return import_config.ANSIColors.RED;
|
|
173
|
+
default:
|
|
174
|
+
return import_config.ANSIColors.BLUE;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
for (const s of dictionariesStatuses) {
|
|
178
|
+
const icon = iconFor(s.status);
|
|
179
|
+
const color = colorFor(s.status);
|
|
180
|
+
appLogger(
|
|
181
|
+
` - ${s.dictionaryKey} ${import_config.ANSIColors.GREY}[${color}${icon} ${s.status}${import_config.ANSIColors.GREY}]${import_config.ANSIColors.RESET}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
137
184
|
for (const statusObj of dictionariesStatuses) {
|
|
138
185
|
if (statusObj.errorMessage) {
|
|
139
186
|
appLogger(statusObj.errorMessage, {
|
|
@@ -147,51 +194,6 @@ const pull = async (options) => {
|
|
|
147
194
|
});
|
|
148
195
|
}
|
|
149
196
|
};
|
|
150
|
-
const getStatusIcon = (status) => {
|
|
151
|
-
const statusIcons = {
|
|
152
|
-
pending: "\u23F2",
|
|
153
|
-
fetching: "",
|
|
154
|
-
// Spinner handled separately
|
|
155
|
-
"up-to-date": "\u2714",
|
|
156
|
-
updated: "\u2714",
|
|
157
|
-
fetched: "\u2714",
|
|
158
|
-
error: "\u2716"
|
|
159
|
-
};
|
|
160
|
-
return statusIcons[status] ?? "";
|
|
161
|
-
};
|
|
162
|
-
const getStatusLine = (statusObj) => {
|
|
163
|
-
let icon = getStatusIcon(statusObj.status);
|
|
164
|
-
let colorStart = "";
|
|
165
|
-
let colorEnd = "";
|
|
166
|
-
if (statusObj.status === "fetching") {
|
|
167
|
-
icon = spinnerFrames[statusObj.spinnerFrameIndex % spinnerFrames.length];
|
|
168
|
-
colorStart = BLUE;
|
|
169
|
-
colorEnd = RESET;
|
|
170
|
-
} else if (statusObj.status === "error") {
|
|
171
|
-
colorStart = RED;
|
|
172
|
-
colorEnd = RESET;
|
|
173
|
-
} else if (statusObj.status === "fetched" || statusObj.status === "imported" || statusObj.status === "updated" || statusObj.status === "up-to-date") {
|
|
174
|
-
colorStart = GREEN;
|
|
175
|
-
colorEnd = RESET;
|
|
176
|
-
} else if (statusObj.status === "reimported in JSON" || statusObj.status === "reimported in new location") {
|
|
177
|
-
colorStart = YELLOW;
|
|
178
|
-
colorEnd = RESET;
|
|
179
|
-
} else {
|
|
180
|
-
colorStart = GREY;
|
|
181
|
-
colorEnd = RESET;
|
|
182
|
-
}
|
|
183
|
-
return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;
|
|
184
|
-
};
|
|
185
|
-
const updateAllStatusLines = (dictionariesStatuses) => {
|
|
186
|
-
readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);
|
|
187
|
-
for (const statusObj of dictionariesStatuses) {
|
|
188
|
-
readline.clearLine(process.stdout, 0);
|
|
189
|
-
if (statusObj.status === "fetching") {
|
|
190
|
-
statusObj.spinnerFrameIndex = (statusObj.spinnerFrameIndex + 1) % spinnerFrames.length;
|
|
191
|
-
}
|
|
192
|
-
process.stdout.write(getStatusLine(statusObj) + "\n");
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
197
|
// Annotate the CommonJS export names for ESM import in node:
|
|
196
198
|
0 && (module.exports = {
|
|
197
199
|
pull
|
package/dist/cjs/pull.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import { getIntlayerAPI } from '@intlayer/api';\nimport {\n writeContentDeclaration,\n type DictionaryStatus,\n} from '@intlayer/chokidar';\nimport {\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n} from '@intlayer/config';\n\nimport type { Dictionary } from '@intlayer/core';\nimport pLimit from 'p-limit';\nimport * as readline from 'readline';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus;\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.oAuth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":["pLimit"]}
|
|
1
|
+
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n parallelize,\n writeContentDeclaration,\n type DictionaryStatus,\n} from '@intlayer/chokidar';\nimport {\n ANSIColors,\n ESMxCJSRequire,\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n} from '@intlayer/config';\nimport type { Dictionary } from '@intlayer/core';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { PullLogger, type PullStatus } from './pullLog';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override, {\n config: {\n prefix: '',\n },\n });\n\n try {\n const config = getConfiguration(options?.configOptions);\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, number> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries!.includes(key)\n )\n );\n }\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.content.mainDir,\n 'remote_dictionaries.cjs'\n );\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (ESMxCJSRequire(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAt]) => {\n if (!remoteUpdatedAt) return true;\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAt]) => {\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\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 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\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.dictionaryKey} ${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 } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoC;AACpC,sBAIO;AACP,oBAMO;AAEP,gBAA2B;AAC3B,kBAAqB;AACrB,qBAA4C;AAmBrC,MAAM,OAAO,OAAO,YAAyC;AAClE,QAAM,gBAAY,4BAAa,SAAS,eAAe,UAAU;AAAA,IAC/D,QAAQ;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,MAAI;AACF,UAAM,aAAS,gCAAiB,SAAS,aAAa;AACtD,UAAM,EAAE,UAAU,aAAa,IAAI,OAAO;AAE1C,QAAI,CAAC,YAAY,CAAC,cAAc;AAC9B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,kBAAc,gCAAoB,QAAW,MAAM;AAGzD,UAAM,uCACJ,MAAM,YAAY,WAAW,+BAA+B;AAE9D,QAAI,CAAC,qCAAqC,MAAM;AAC9C,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAEA,QAAI,qCACF,qCAAqC;AAGvC,QAAI,SAAS,cAAc;AACzB,2CAAqC,OAAO;AAAA,QAC1C,OAAO,QAAQ,kCAAkC,EAAE;AAAA,UAAO,CAAC,CAAC,GAAG,MAC7D,QAAQ,aAAc,SAAS,GAAG;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAGA,UAAM,6BAAyB;AAAA,MAC7B,OAAO,QAAQ;AAAA,MACf;AAAA,IACF;AACA,UAAM,+BAAgD;AAAA,MACpD;AAAA,IACF,QACK,8BAAe,sBAAsB,IACtC,CAAC;AAGL,UAAM,UAAU,OAAO,QAAQ,kCAAkC;AACjE,UAAM,cAAc,QACjB,OAAO,CAAC,CAAC,KAAK,eAAe,MAAM;AAClC,UAAI,CAAC,gBAAiB,QAAO;AAC7B,YAAM,QAAS,yBAAiC,GAAG;AACnD,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,oBAAqB,OAAe;AAI1C,YAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,EAAE,QAAQ,IACpC;AACR,UAAI,OAAO,mBAAmB,SAAU,QAAO;AAC/C,aAAO,kBAAkB;AAAA,IAC3B,CAAC,EACA,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AAErB,UAAM,aAAa,QAChB,OAAO,CAAC,CAAC,KAAK,eAAe,MAAM;AAClC,YAAM,QAAS,yBAAiC,GAAG;AACnD,YAAM,oBAAqB,OAAe;AAI1C,YAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,EAAE,QAAQ,IACpC;AACR,aACE,OAAO,mBAAmB,YAC1B,OAAO,oBAAoB,YAC3B,kBAAkB;AAAA,IAEtB,CAAC,EACA,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AAGrB,QAAI,QAAQ,WAAW,GAAG;AACxB,gBAAU,4BAA4B;AAAA,QACpC,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AAEA,cAAU,wBAAwB;AAGlC,UAAM,uBAA6C;AAAA,MACjD,GAAG,WAAW,IAAI,CAAC,mBAAmB;AAAA,QACpC;AAAA,QACA,QAAQ;AAAA,MACV,EAAE;AAAA,MACF,GAAG,YAAY,IAAI,CAAC,mBAAmB;AAAA,QACrC;AAAA,QACA,QAAQ;AAAA,MACV,EAAE;AAAA,IACJ;AAGA,UAAM,SAAS,IAAI,0BAAW;AAC9B,WAAO;AAAA,MACL,qBAAqB,IAAgB,CAAC,OAAO;AAAA,QAC3C,eAAe,EAAE;AAAA,QACjB,QAAQ,EAAE;AAAA,MACZ,EAAE;AAAA,IACJ;AAEA,UAAM,kCAAgD,CAAC;AAEvD,UAAM,oBAAoB,OACxB,cACkB;AAClB,YAAM,WACJ,UAAU,WAAW,cAAc,UAAU,WAAW;AAE1D,UAAI,CAAC,UAAU;AACb,kBAAU,SAAS;AACnB,eAAO,OAAO;AAAA,UACZ,EAAE,eAAe,UAAU,eAAe,QAAQ,WAAW;AAAA,QAC/D,CAAC;AAAA,MACH;AAEA,UAAI;AACF,YAAI;AAEJ,YAAI,UAAU;AACZ,6BAAmB,yBACjB,UAAU,aACZ;AAAA,QACF;AAEA,YAAI,CAAC,kBAAkB;AAErB,gBAAM,sBACJ,MAAM,YAAY,WAAW,cAAc,UAAU,aAAa;AAEpE,6BAAmB,oBAAoB;AAAA,QACzC;AAEA,YAAI,CAAC,kBAAkB;AACrB,gBAAM,IAAI;AAAA,YACR,cAAc,UAAU,aAAa;AAAA,UACvC;AAAA,QACF;AAGA,cAAM,EAAE,OAAO,IAAI,UAAM;AAAA,UACvB;AAAA,UACA;AAAA,UACA,SAAS;AAAA,QACX;AAEA,kBAAU,SAAS;AACnB,eAAO,OAAO,CAAC,EAAE,eAAe,UAAU,eAAe,OAAO,CAAC,CAAC;AAElE,wCAAgC,KAAK,gBAAgB;AAAA,MACvD,SAAS,OAAO;AACd,kBAAU,SAAS;AACnB,kBAAU,QAAQ;AAClB,kBAAU,eAAe,6BAA6B,UAAU,aAAa,KAAK,KAAK;AACvF,eAAO,OAAO;AAAA,UACZ,EAAE,eAAe,UAAU,eAAe,QAAQ,QAAQ;AAAA,QAC5D,CAAC;AAAA,MACH;AAAA,IACF;AAGA,cAAM,6BAAY,sBAAsB,mBAAmB,CAAC;AAG5D,WAAO,OAAO;AAGd,UAAM,UAAU,CAAC,WAAyC;AACxD,cAAQ,QAAQ;AAAA,QACd,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT;AACE,iBAAO;AAAA,MACX;AAAA,IACF;AAEA,UAAM,WAAW,CAAC,WAAyC;AACzD,cAAQ,QAAQ;AAAA,QACd,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH,iBAAO,yBAAW;AAAA,QACpB,KAAK;AAAA,QACL,KAAK;AACH,iBAAO,yBAAW;AAAA,QACpB,KAAK;AACH,iBAAO,yBAAW;AAAA,QACpB;AACE,iBAAO,yBAAW;AAAA,MACtB;AAAA,IACF;AAEA,eAAW,KAAK,sBAAsB;AACpC,YAAM,OAAO,QAAQ,EAAE,MAAM;AAC7B,YAAM,QAAQ,SAAS,EAAE,MAAM;AAC/B;AAAA,QACE,MAAM,EAAE,aAAa,IAAI,yBAAW,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,EAAE,MAAM,GAAG,yBAAW,IAAI,IAAI,yBAAW,KAAK;AAAA,MAC5G;AAAA,IACF;AAGA,eAAW,aAAa,sBAAsB;AAC5C,UAAI,UAAU,cAAc;AAC1B,kBAAU,UAAU,cAAc;AAAA,UAChC,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,cAAU,OAAO;AAAA,MACf,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var pullLog_exports = {};
|
|
20
|
+
__export(pullLog_exports, {
|
|
21
|
+
PullLogger: () => PullLogger
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(pullLog_exports);
|
|
24
|
+
var import_config = require("@intlayer/config");
|
|
25
|
+
class PullLogger {
|
|
26
|
+
statuses = [];
|
|
27
|
+
spinnerTimer = null;
|
|
28
|
+
spinnerIndex = 0;
|
|
29
|
+
renderedLines = 0;
|
|
30
|
+
spinnerFrames = import_config.spinnerFrames;
|
|
31
|
+
isFinished = false;
|
|
32
|
+
prefix;
|
|
33
|
+
lastRenderedState = "";
|
|
34
|
+
constructor() {
|
|
35
|
+
const configuration = (0, import_config.getConfiguration)();
|
|
36
|
+
this.prefix = configuration.log.prefix;
|
|
37
|
+
}
|
|
38
|
+
update(newStatuses) {
|
|
39
|
+
if (this.isFinished) return;
|
|
40
|
+
for (const status of newStatuses) {
|
|
41
|
+
const index = this.statuses.findIndex(
|
|
42
|
+
(s) => s.dictionaryKey === status.dictionaryKey
|
|
43
|
+
);
|
|
44
|
+
if (index >= 0) {
|
|
45
|
+
this.statuses[index] = status;
|
|
46
|
+
} else {
|
|
47
|
+
this.statuses.push(status);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
this.startSpinner();
|
|
51
|
+
this.render();
|
|
52
|
+
}
|
|
53
|
+
finish() {
|
|
54
|
+
this.isFinished = true;
|
|
55
|
+
this.stopSpinner();
|
|
56
|
+
this.render();
|
|
57
|
+
}
|
|
58
|
+
startSpinner() {
|
|
59
|
+
if (this.spinnerTimer || this.isFinished) return;
|
|
60
|
+
this.spinnerTimer = setInterval(() => {
|
|
61
|
+
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
|
|
62
|
+
this.render();
|
|
63
|
+
}, 100);
|
|
64
|
+
}
|
|
65
|
+
stopSpinner() {
|
|
66
|
+
if (!this.spinnerTimer) return;
|
|
67
|
+
clearInterval(this.spinnerTimer);
|
|
68
|
+
this.spinnerTimer = null;
|
|
69
|
+
}
|
|
70
|
+
render() {
|
|
71
|
+
const { total, done, success, errors } = this.computeProgress();
|
|
72
|
+
const frame = this.spinnerFrames[this.spinnerIndex];
|
|
73
|
+
const lines = [];
|
|
74
|
+
const isDone = done === total;
|
|
75
|
+
const progressLabel = `dictionaries: ${done}/${total}`;
|
|
76
|
+
const details = [];
|
|
77
|
+
if (success > 0) details.push(`ok: ${success}`);
|
|
78
|
+
if (errors > 0) details.push((0, import_config.colorize)(`errors: ${errors}`, import_config.ANSIColors.RED));
|
|
79
|
+
const suffix = details.length > 0 ? ` (${details.join(", ")})` : "";
|
|
80
|
+
if (isDone) {
|
|
81
|
+
lines.push(
|
|
82
|
+
`${this.prefix} ${(0, import_config.colorize)("\u2714", import_config.ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
lines.push(
|
|
86
|
+
`${this.prefix} ${(0, import_config.colorize)(frame, import_config.ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const currentState = lines.join("\n");
|
|
90
|
+
if (currentState === this.lastRenderedState) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.lastRenderedState = currentState;
|
|
94
|
+
if (this.renderedLines > 0) {
|
|
95
|
+
process.stdout.write(`\x1B[${this.renderedLines}F`);
|
|
96
|
+
}
|
|
97
|
+
const totalLinesToClear = Math.max(this.renderedLines, lines.length);
|
|
98
|
+
for (let i = 0; i < totalLinesToClear; i++) {
|
|
99
|
+
process.stdout.write("\x1B[2K");
|
|
100
|
+
const line = lines[i];
|
|
101
|
+
if (line !== void 0) {
|
|
102
|
+
process.stdout.write(line);
|
|
103
|
+
}
|
|
104
|
+
process.stdout.write("\n");
|
|
105
|
+
}
|
|
106
|
+
this.renderedLines = lines.length;
|
|
107
|
+
}
|
|
108
|
+
computeProgress() {
|
|
109
|
+
const keys = new Set(this.statuses.map((s) => s.dictionaryKey));
|
|
110
|
+
const doneSet = /* @__PURE__ */ new Set([
|
|
111
|
+
"fetched",
|
|
112
|
+
"imported",
|
|
113
|
+
"updated",
|
|
114
|
+
"up-to-date",
|
|
115
|
+
"reimported in JSON",
|
|
116
|
+
"new content file",
|
|
117
|
+
"error"
|
|
118
|
+
]);
|
|
119
|
+
const successesSet = /* @__PURE__ */ new Set([
|
|
120
|
+
"fetched",
|
|
121
|
+
"imported",
|
|
122
|
+
"updated",
|
|
123
|
+
"up-to-date",
|
|
124
|
+
"reimported in JSON",
|
|
125
|
+
"new content file"
|
|
126
|
+
]);
|
|
127
|
+
const done = this.statuses.filter(
|
|
128
|
+
(s) => doneSet.has(s.status)
|
|
129
|
+
).length;
|
|
130
|
+
const success = this.statuses.filter(
|
|
131
|
+
(s) => successesSet.has(s.status)
|
|
132
|
+
).length;
|
|
133
|
+
const errors = this.statuses.filter((s) => s.status === "error").length;
|
|
134
|
+
return {
|
|
135
|
+
total: keys.size,
|
|
136
|
+
done,
|
|
137
|
+
success,
|
|
138
|
+
errors
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
143
|
+
0 && (module.exports = {
|
|
144
|
+
PullLogger
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=pullLog.cjs.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":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAKO;AAQA,MAAM,WAAW;AAAA,EACd,WAAyB,CAAC;AAAA,EAC1B,eAAsC;AAAA,EACtC,eAAe;AAAA,EACf,gBAAgB;AAAA,EACP,gBAAgB;AAAA,EACzB,aAAa;AAAA,EACJ;AAAA,EACT,oBAA4B;AAAA,EAEpC,cAAc;AACZ,UAAM,oBAAgB,gCAAiB;AACvC,SAAK,SAAS,cAAc,IAAI;AAAA,EAClC;AAAA,EAEA,OAAO,aAA2B;AAChC,QAAI,KAAK,WAAY;AACrB,eAAW,UAAU,aAAa;AAChC,YAAM,QAAQ,KAAK,SAAS;AAAA,QAC1B,CAAC,MAAM,EAAE,kBAAkB,OAAO;AAAA,MACpC;AACA,UAAI,SAAS,GAAG;AACd,aAAK,SAAS,KAAK,IAAI;AAAA,MACzB,OAAO;AACL,aAAK,SAAS,KAAK,MAAM;AAAA,MAC3B;AAAA,IACF;AAEA,SAAK,aAAa;AAClB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,SAAS;AACP,SAAK,aAAa;AAClB,SAAK,YAAY;AACjB,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,eAAe;AACrB,QAAI,KAAK,gBAAgB,KAAK,WAAY;AAC1C,SAAK,eAAe,YAAY,MAAM;AACpC,WAAK,gBAAgB,KAAK,eAAe,KAAK,KAAK,cAAc;AACjE,WAAK,OAAO;AAAA,IACd,GAAG,GAAG;AAAA,EACR;AAAA,EAEQ,cAAc;AACpB,QAAI,CAAC,KAAK,aAAc;AACxB,kBAAc,KAAK,YAAY;AAC/B,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,SAAS;AACf,UAAM,EAAE,OAAO,MAAM,SAAS,OAAO,IAAI,KAAK,gBAAgB;AAE9D,UAAM,QAAQ,KAAK,cAAc,KAAK,YAAY;AAClD,UAAM,QAAkB,CAAC;AAEzB,UAAM,SAAS,SAAS;AACxB,UAAM,gBAAgB,iBAAiB,IAAI,IAAI,KAAK;AACpD,UAAM,UAAoB,CAAC;AAC3B,QAAI,UAAU,EAAG,SAAQ,KAAK,OAAO,OAAO,EAAE;AAC9C,QAAI,SAAS,EAAG,SAAQ,SAAK,wBAAS,WAAW,MAAM,IAAI,yBAAW,GAAG,CAAC;AAE1E,UAAM,SAAS,QAAQ,SAAS,IAAI,KAAK,QAAQ,KAAK,IAAI,CAAC,MAAM;AAEjE,QAAI,QAAQ;AACV,YAAM;AAAA,QACJ,GAAG,KAAK,MAAM,QAAI,wBAAS,UAAK,yBAAW,KAAK,CAAC,YAAY,aAAa,GAAG,MAAM;AAAA,MACrF;AAAA,IACF,OAAO;AACL,YAAM;AAAA,QACJ,GAAG,KAAK,MAAM,QAAI,wBAAS,OAAO,yBAAW,IAAI,CAAC,aAAa,aAAa,GAAG,MAAM;AAAA,MACvF;AAAA,IACF;AAEA,UAAM,eAAe,MAAM,KAAK,IAAI;AACpC,QAAI,iBAAiB,KAAK,mBAAmB;AAC3C;AAAA,IACF;AACA,SAAK,oBAAoB;AAEzB,QAAI,KAAK,gBAAgB,GAAG;AAC1B,cAAQ,OAAO,MAAM,QAAQ,KAAK,aAAa,GAAG;AAAA,IACpD;AAEA,UAAM,oBAAoB,KAAK,IAAI,KAAK,eAAe,MAAM,MAAM;AACnE,aAAS,IAAI,GAAG,IAAI,mBAAmB,KAAK;AAC1C,cAAQ,OAAO,MAAM,SAAS;AAC9B,YAAM,OAAO,MAAM,CAAC;AACpB,UAAI,SAAS,QAAW;AACtB,gBAAQ,OAAO,MAAM,IAAI;AAAA,MAC3B;AACA,cAAQ,OAAO,MAAM,IAAI;AAAA,IAC3B;AAEA,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA,EAEQ,kBAAkB;AACxB,UAAM,OAAO,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC;AAE9D,UAAM,UAAU,oBAAI,IAAgC;AAAA,MAClD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAU;AAEV,UAAM,eAAe,oBAAI,IAAsB;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAU;AAEV,UAAM,OAAO,KAAK,SAAS;AAAA,MAAO,CAAC,MACjC,QAAQ,IAAI,EAAE,MAAa;AAAA,IAC7B,EAAE;AACF,UAAM,UAAU,KAAK,SAAS;AAAA,MAAO,CAAC,MACpC,aAAa,IAAI,EAAE,MAAa;AAAA,IAClC,EAAE;AACF,UAAM,SAAS,KAAK,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;AAEjE,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|