@intlayer/cli 5.4.2 → 5.5.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/build.cjs +1 -1
- package/dist/cjs/build.cjs.map +1 -1
- package/dist/cjs/cli.cjs +222 -19
- package/dist/cjs/cli.cjs.map +1 -1
- package/dist/cjs/config.cjs +3 -6
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/fill.cjs +360 -0
- package/dist/cjs/fill.cjs.map +1 -0
- package/dist/cjs/index.cjs +6 -6
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/listContentDeclaration.cjs +3 -7
- package/dist/cjs/listContentDeclaration.cjs.map +1 -1
- package/dist/cjs/pull.cjs +3 -3
- package/dist/cjs/pull.cjs.map +1 -1
- package/dist/cjs/push.cjs +24 -54
- package/dist/cjs/push.cjs.map +1 -1
- package/dist/cjs/pushConfig.cjs +1 -1
- package/dist/cjs/pushConfig.cjs.map +1 -1
- package/dist/esm/build.mjs +1 -1
- package/dist/esm/build.mjs.map +1 -1
- package/dist/esm/cli.mjs +211 -18
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/config.mjs +4 -8
- package/dist/esm/config.mjs.map +1 -1
- package/dist/esm/fill.mjs +338 -0
- package/dist/esm/fill.mjs.map +1 -0
- package/dist/esm/index.mjs +3 -3
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/listContentDeclaration.mjs +5 -9
- package/dist/esm/listContentDeclaration.mjs.map +1 -1
- package/dist/esm/pull.mjs +5 -5
- package/dist/esm/pull.mjs.map +1 -1
- package/dist/esm/push.mjs +26 -56
- package/dist/esm/push.mjs.map +1 -1
- package/dist/esm/pushConfig.mjs +1 -1
- package/dist/esm/pushConfig.mjs.map +1 -1
- package/dist/types/build.d.ts +2 -1
- package/dist/types/build.d.ts.map +1 -1
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts +2 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/fill.d.ts +27 -0
- package/dist/types/fill.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/listContentDeclaration.d.ts +4 -3
- package/dist/types/listContentDeclaration.d.ts.map +1 -1
- package/dist/types/pull.d.ts +2 -1
- package/dist/types/pull.d.ts.map +1 -1
- package/dist/types/push.d.ts +4 -2
- package/dist/types/push.d.ts.map +1 -1
- package/dist/types/pushConfig.d.ts +2 -1
- package/dist/types/pushConfig.d.ts.map +1 -1
- package/package.json +13 -12
- package/dist/cjs/audit.cjs +0 -126
- package/dist/cjs/audit.cjs.map +0 -1
- package/dist/esm/audit.mjs +0 -94
- package/dist/esm/audit.mjs.map +0 -1
- package/dist/types/audit.d.ts +0 -38
- package/dist/types/audit.d.ts.map +0 -1
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
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
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var fill_exports = {};
|
|
30
|
+
__export(fill_exports, {
|
|
31
|
+
fill: () => fill
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(fill_exports);
|
|
34
|
+
var import_api = require("@intlayer/api");
|
|
35
|
+
var import_chokidar = require("@intlayer/chokidar");
|
|
36
|
+
var import_config = require("@intlayer/config");
|
|
37
|
+
var import_core = require("@intlayer/core");
|
|
38
|
+
var import_dictionaries_entry = __toESM(require("@intlayer/dictionaries-entry"));
|
|
39
|
+
var import_unmerged_dictionaries_entry = __toESM(require("@intlayer/unmerged-dictionaries-entry"));
|
|
40
|
+
var import_path = require("path");
|
|
41
|
+
const ensureArray = (value) => [value].flat();
|
|
42
|
+
const getTargetDictionary = async (options) => {
|
|
43
|
+
const configuration = (0, import_config.getConfiguration)(options.configOptions);
|
|
44
|
+
const { baseDir } = configuration.content;
|
|
45
|
+
let result = Object.values(import_unmerged_dictionaries_entry.default).flat();
|
|
46
|
+
if (typeof options.file !== "undefined") {
|
|
47
|
+
const fileArray = ensureArray(options.file);
|
|
48
|
+
const absoluteFilePaths = fileArray.map((file) => (0, import_path.join)(baseDir, file));
|
|
49
|
+
result = result.filter(
|
|
50
|
+
(dict) => dict.filePath && (absoluteFilePaths.includes(dict.filePath) || absoluteFilePaths.includes((0, import_path.join)(baseDir, dict.filePath)))
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
if (typeof options.keys !== "undefined") {
|
|
54
|
+
result = result.filter(
|
|
55
|
+
(dict) => ensureArray(options.keys)?.includes(dict.key)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (typeof options.excludedKeys !== "undefined") {
|
|
59
|
+
result = result.filter(
|
|
60
|
+
(dict) => !ensureArray(options.excludedKeys)?.includes(dict.key)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (typeof options.pathFilter !== "undefined") {
|
|
64
|
+
result = result.filter(
|
|
65
|
+
(dict) => ensureArray(options.pathFilter)?.includes(dict.filePath ?? "")
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (typeof options.filter !== "undefined") {
|
|
69
|
+
result = result.filter(options.filter);
|
|
70
|
+
}
|
|
71
|
+
const gitOptions = options.gitOptions;
|
|
72
|
+
if (gitOptions) {
|
|
73
|
+
const gitChangedFiles = await (0, import_chokidar.listGitFiles)(gitOptions);
|
|
74
|
+
if (gitChangedFiles) {
|
|
75
|
+
result = result.filter((dict) => {
|
|
76
|
+
if (!dict.filePath) return false;
|
|
77
|
+
return gitChangedFiles.some((gitFile) => dict.filePath === gitFile);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result.filter((dict) => !dict.autoFilled);
|
|
82
|
+
};
|
|
83
|
+
const transformUriToAbsolutePath = (uri, filePath, baseDir) => {
|
|
84
|
+
if (uri.startsWith("/")) {
|
|
85
|
+
return (0, import_path.join)(baseDir, uri);
|
|
86
|
+
}
|
|
87
|
+
if (uri.startsWith("./")) {
|
|
88
|
+
return (0, import_path.join)((0, import_path.dirname)(filePath), uri);
|
|
89
|
+
}
|
|
90
|
+
return filePath;
|
|
91
|
+
};
|
|
92
|
+
const formatAutoFillData = (autoFillOptions, localeList, filePath, dictionaryKey, configuration) => {
|
|
93
|
+
const outputContentDeclarationFile = [];
|
|
94
|
+
if (!Boolean(autoFillOptions)) return outputContentDeclarationFile;
|
|
95
|
+
if (autoFillOptions === true) {
|
|
96
|
+
let jsonFilePath = filePath.replace((0, import_path.extname)(filePath), ".json");
|
|
97
|
+
if (filePath === jsonFilePath) {
|
|
98
|
+
jsonFilePath = jsonFilePath.replace((0, import_path.extname)(jsonFilePath), ".fill.json");
|
|
99
|
+
}
|
|
100
|
+
outputContentDeclarationFile.push({
|
|
101
|
+
localeList,
|
|
102
|
+
filePath: jsonFilePath
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (typeof autoFillOptions === "string") {
|
|
106
|
+
if (autoFillOptions.includes("{{locale}}")) {
|
|
107
|
+
const output = localeList.map((locale) => ({
|
|
108
|
+
localeList: [locale],
|
|
109
|
+
filePath: transformUriToAbsolutePath(
|
|
110
|
+
autoFillOptions.replace("{{locale}}", locale).replace("{{key}}", dictionaryKey),
|
|
111
|
+
filePath,
|
|
112
|
+
configuration.content.baseDir
|
|
113
|
+
)
|
|
114
|
+
}));
|
|
115
|
+
outputContentDeclarationFile.push(...output);
|
|
116
|
+
} else {
|
|
117
|
+
outputContentDeclarationFile.push({
|
|
118
|
+
localeList,
|
|
119
|
+
filePath: transformUriToAbsolutePath(
|
|
120
|
+
autoFillOptions,
|
|
121
|
+
filePath,
|
|
122
|
+
configuration.content.baseDir
|
|
123
|
+
)
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return outputContentDeclarationFile;
|
|
127
|
+
}
|
|
128
|
+
if (typeof autoFillOptions === "object") {
|
|
129
|
+
const localeList2 = Object.keys(autoFillOptions).filter(
|
|
130
|
+
(locale) => typeof autoFillOptions[locale] === "string"
|
|
131
|
+
);
|
|
132
|
+
const output = localeList2.map((locale) => ({
|
|
133
|
+
localeList: [locale],
|
|
134
|
+
filePath: transformUriToAbsolutePath(
|
|
135
|
+
autoFillOptions[locale].replace("{{key}}", dictionaryKey),
|
|
136
|
+
filePath,
|
|
137
|
+
configuration.content.baseDir
|
|
138
|
+
)
|
|
139
|
+
}));
|
|
140
|
+
const groupedByFilePath = output.reduce((acc, curr) => {
|
|
141
|
+
const existing = acc.find((item) => item.filePath === curr.filePath);
|
|
142
|
+
if (existing) {
|
|
143
|
+
existing.localeList.push(...curr.localeList);
|
|
144
|
+
} else {
|
|
145
|
+
acc.push(curr);
|
|
146
|
+
}
|
|
147
|
+
return acc;
|
|
148
|
+
}, []);
|
|
149
|
+
outputContentDeclarationFile.push(...groupedByFilePath);
|
|
150
|
+
}
|
|
151
|
+
return outputContentDeclarationFile;
|
|
152
|
+
};
|
|
153
|
+
const autoFill = async (fullDictionary, contentDeclarationFile, autoFillOptions, outputLocales, parentLocales, configuration) => {
|
|
154
|
+
let localeList = (outputLocales ?? configuration.internationalization.locales).filter((locale) => !parentLocales?.includes(locale));
|
|
155
|
+
const filePath = contentDeclarationFile.filePath;
|
|
156
|
+
if (!filePath) {
|
|
157
|
+
(0, import_config.appLogger)("No file path found for dictionary", {
|
|
158
|
+
level: "error"
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const autoFillData = formatAutoFillData(
|
|
163
|
+
autoFillOptions,
|
|
164
|
+
localeList,
|
|
165
|
+
filePath,
|
|
166
|
+
fullDictionary.key,
|
|
167
|
+
configuration
|
|
168
|
+
);
|
|
169
|
+
(0, import_config.appLogger)(`Auto fill data: ${JSON.stringify(autoFillData, null, 2)}`, {
|
|
170
|
+
level: "info",
|
|
171
|
+
isVerbose: true
|
|
172
|
+
});
|
|
173
|
+
for await (const output of autoFillData) {
|
|
174
|
+
const reducedDictionary = (0, import_chokidar.reduceDictionaryContent)(
|
|
175
|
+
fullDictionary,
|
|
176
|
+
contentDeclarationFile
|
|
177
|
+
);
|
|
178
|
+
const isPerLocaleDeclarationFile = output.localeList.length === 1;
|
|
179
|
+
if (isPerLocaleDeclarationFile) {
|
|
180
|
+
const sourceLocale = output.localeList[0];
|
|
181
|
+
const sourceLocaleContent = (0, import_core.getLocalisedContent)(
|
|
182
|
+
reducedDictionary,
|
|
183
|
+
sourceLocale,
|
|
184
|
+
{ dictionaryKey: reducedDictionary.key, keyPath: [] }
|
|
185
|
+
);
|
|
186
|
+
await (0, import_chokidar.writeContentDeclaration)({
|
|
187
|
+
...fullDictionary,
|
|
188
|
+
locale: sourceLocale,
|
|
189
|
+
autoFilled: true,
|
|
190
|
+
autoFill: void 0,
|
|
191
|
+
content: sourceLocaleContent.content,
|
|
192
|
+
filePath: output.filePath
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
const filteredDictionary = (0, import_chokidar.filterDictionaryLocales)(
|
|
196
|
+
reducedDictionary,
|
|
197
|
+
output.localeList
|
|
198
|
+
);
|
|
199
|
+
await (0, import_chokidar.writeContentDeclaration)({
|
|
200
|
+
...fullDictionary,
|
|
201
|
+
autoFilled: true,
|
|
202
|
+
autoFill: void 0,
|
|
203
|
+
content: filteredDictionary.content,
|
|
204
|
+
filePath: output.filePath
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const fill = async (options) => {
|
|
210
|
+
const configuration = (0, import_config.getConfiguration)(options.configOptions);
|
|
211
|
+
const { defaultLocale, locales } = configuration.internationalization;
|
|
212
|
+
const mode = options.mode ?? "review";
|
|
213
|
+
const baseLocale = options.sourceLocale ?? defaultLocale;
|
|
214
|
+
if (!configuration.editor.clientId && !options.aiOptions?.apiKey) {
|
|
215
|
+
(0, import_config.appLogger)("AI options or API key not provided. Skipping AI translation.", {
|
|
216
|
+
level: "error"
|
|
217
|
+
});
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
(0, import_config.appLogger)(["Starting fill function with options:", options], {
|
|
221
|
+
level: "info"
|
|
222
|
+
});
|
|
223
|
+
const targetUnmergedDictionaries = await getTargetDictionary(options);
|
|
224
|
+
const outputLocalesList = (options.outputLocales ? ensureArray(options.outputLocales) : locales).filter(
|
|
225
|
+
(locale) => (
|
|
226
|
+
// If mode is review, translate all locales
|
|
227
|
+
// If mode is complete, translate only the locales that are not the source locale
|
|
228
|
+
mode === "review" ? true : locale !== baseLocale
|
|
229
|
+
)
|
|
230
|
+
);
|
|
231
|
+
const affectedDictionaryKeys = /* @__PURE__ */ new Set();
|
|
232
|
+
targetUnmergedDictionaries.forEach((dict) => {
|
|
233
|
+
affectedDictionaryKeys.add(dict.key);
|
|
234
|
+
});
|
|
235
|
+
(0, import_config.appLogger)(
|
|
236
|
+
[
|
|
237
|
+
"Affected dictionary keys for processing:",
|
|
238
|
+
Array.from(affectedDictionaryKeys).join(", ")
|
|
239
|
+
],
|
|
240
|
+
{
|
|
241
|
+
isVerbose: true
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
for (const targetUnmergedDictionary of targetUnmergedDictionaries) {
|
|
245
|
+
const dictionaryKey = targetUnmergedDictionary.key;
|
|
246
|
+
const mainDictionaryToProcess = import_dictionaries_entry.default[dictionaryKey];
|
|
247
|
+
const sourceLocale = targetUnmergedDictionary.locale ?? baseLocale;
|
|
248
|
+
if (!mainDictionaryToProcess) {
|
|
249
|
+
(0, import_config.appLogger)(
|
|
250
|
+
`Dictionary with key "${dictionaryKey}" not found in dictionariesRecord. Skipping.`,
|
|
251
|
+
{
|
|
252
|
+
level: "warn"
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
(0, import_config.appLogger)(
|
|
258
|
+
`Processing content declaration: ${targetUnmergedDictionary.filePath}`,
|
|
259
|
+
{
|
|
260
|
+
isVerbose: true
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
const sourceLocaleContent = (0, import_core.getLocalisedContent)(
|
|
264
|
+
mainDictionaryToProcess,
|
|
265
|
+
sourceLocale,
|
|
266
|
+
{ dictionaryKey, keyPath: [] }
|
|
267
|
+
);
|
|
268
|
+
if (Object.keys(sourceLocaleContent).length === 0) {
|
|
269
|
+
(0, import_config.appLogger)(
|
|
270
|
+
`No content found for dictionary ${dictionaryKey} in source locale ${sourceLocale}. Skipping translation for this dictionary.`,
|
|
271
|
+
{
|
|
272
|
+
level: "warn"
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const result = [];
|
|
278
|
+
for await (const targetLocale of outputLocalesList) {
|
|
279
|
+
(0, import_config.appLogger)(
|
|
280
|
+
`Preparing translation for ${dictionaryKey} from ${sourceLocale} to ${targetLocale}`,
|
|
281
|
+
{
|
|
282
|
+
isVerbose: true
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
const presetOutputContent = (0, import_core.getLocalisedContent)(
|
|
286
|
+
mainDictionaryToProcess,
|
|
287
|
+
targetLocale,
|
|
288
|
+
{ dictionaryKey, keyPath: [] }
|
|
289
|
+
);
|
|
290
|
+
try {
|
|
291
|
+
const translationResult = await (0, import_api.getAiAPI)().translateJSON({
|
|
292
|
+
entryFileContent: sourceLocaleContent.content,
|
|
293
|
+
// Should be JSON, ensure getLocalisedContent provides this.
|
|
294
|
+
presetOutputContent: presetOutputContent.content,
|
|
295
|
+
// Should be JSON
|
|
296
|
+
dictionaryDescription: mainDictionaryToProcess.description,
|
|
297
|
+
entryLocale: sourceLocale,
|
|
298
|
+
outputLocale: targetLocale,
|
|
299
|
+
mode,
|
|
300
|
+
aiOptions: options.aiOptions
|
|
301
|
+
});
|
|
302
|
+
if (!translationResult.data?.fileContent) {
|
|
303
|
+
(0, import_config.appLogger)(
|
|
304
|
+
`No content result found for ${dictionaryKey} to ${targetLocale}`,
|
|
305
|
+
{
|
|
306
|
+
level: "error"
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const processedPerLocaleDictionary = (0, import_chokidar.processPerLocaleDictionary)({
|
|
312
|
+
...mainDictionaryToProcess,
|
|
313
|
+
content: translationResult.data?.fileContent,
|
|
314
|
+
locale: targetLocale
|
|
315
|
+
});
|
|
316
|
+
result.push(processedPerLocaleDictionary);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
(0, import_config.appLogger)(
|
|
319
|
+
`Error filling ${dictionaryKey} to ${targetLocale}:` + error,
|
|
320
|
+
{
|
|
321
|
+
level: "error"
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const dictionaryToMerge = mode === "review" ? [...result, mainDictionaryToProcess] : [mainDictionaryToProcess, ...result];
|
|
327
|
+
const mergedResults = (0, import_chokidar.mergeDictionaries)(dictionaryToMerge);
|
|
328
|
+
let formattedDict = targetUnmergedDictionary;
|
|
329
|
+
if (formattedDict.locale) {
|
|
330
|
+
const presetOutputContent = (0, import_core.getLocalisedContent)(
|
|
331
|
+
mainDictionaryToProcess,
|
|
332
|
+
formattedDict.locale,
|
|
333
|
+
{ dictionaryKey, keyPath: [] }
|
|
334
|
+
);
|
|
335
|
+
formattedDict = {
|
|
336
|
+
...formattedDict,
|
|
337
|
+
content: presetOutputContent.content
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
const reducedResult = (0, import_chokidar.reduceDictionaryContent)(mergedResults, formattedDict);
|
|
341
|
+
await (0, import_chokidar.writeContentDeclaration)(
|
|
342
|
+
{ ...formattedDict, content: reducedResult.content },
|
|
343
|
+
configuration,
|
|
344
|
+
formattedDict.filePath
|
|
345
|
+
);
|
|
346
|
+
await autoFill(
|
|
347
|
+
mergedResults,
|
|
348
|
+
targetUnmergedDictionary,
|
|
349
|
+
formattedDict.autoFill,
|
|
350
|
+
outputLocalesList,
|
|
351
|
+
[sourceLocale],
|
|
352
|
+
configuration
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
357
|
+
0 && (module.exports = {
|
|
358
|
+
fill
|
|
359
|
+
});
|
|
360
|
+
//# sourceMappingURL=fill.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fill.ts"],"sourcesContent":["import { AIOptions, getAiAPI } from '@intlayer/api'; // Importing only getAiAPI for now\nimport {\n filterDictionaryLocales,\n listGitFiles,\n ListGitFilesOptions,\n mergeDictionaries,\n processPerLocaleDictionary,\n reduceDictionaryContent,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n appLogger,\n getConfiguration,\n GetConfigurationOptions,\n type IntlayerConfig,\n Locales,\n} from '@intlayer/config';\nimport {\n type AutoFill,\n type ContentNode,\n type Dictionary,\n getLocalisedContent,\n} from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport unmergedDictionariesRecord from '@intlayer/unmerged-dictionaries-entry';\nimport { dirname, extname, join } from 'path';\n\n// Arguments for the fill function\nexport type FillOptions = {\n sourceLocale: Locales;\n outputLocales?: Locales | Locales[];\n file?: string | string[];\n mode?: 'complete' | 'review';\n keys?: string | string[];\n excludedKeys?: string | string[];\n filter?: (entry: Dictionary) => boolean; // DictionaryEntry needs to be defined\n pathFilter?: string | string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n aiOptions?: AIOptions; // Added aiOptions to be passed to translateJSON\n verbose?: boolean;\n};\n\nconst ensureArray = <T>(value: T | T[]): T[] => [value].flat() as T[];\n\nconst getTargetDictionary = async (options: FillOptions) => {\n const configuration = getConfiguration(options.configOptions);\n\n const { baseDir } = configuration.content;\n\n let result = Object.values(unmergedDictionariesRecord).flat();\n\n // 1. if filePath not defined, list all content declaration files based on unmerged dictionaries list\n if (typeof options.file !== 'undefined') {\n const fileArray = ensureArray(options.file);\n const absoluteFilePaths = fileArray.map((file) => join(baseDir, file));\n\n result = result.filter(\n (dict) =>\n dict.filePath &&\n (absoluteFilePaths.includes(dict.filePath) ||\n absoluteFilePaths.includes(join(baseDir, dict.filePath)))\n );\n }\n\n if (typeof options.keys !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.keys)?.includes(dict.key)\n );\n }\n\n if (typeof options.excludedKeys !== 'undefined') {\n result = result.filter(\n (dict) => !ensureArray(options.excludedKeys)?.includes(dict.key)\n );\n }\n\n if (typeof options.pathFilter !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.pathFilter)?.includes(dict.filePath ?? '')\n );\n }\n\n if (typeof options.filter !== 'undefined') {\n result = result.filter(options.filter);\n }\n\n const gitOptions = options.gitOptions;\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n result = result.filter((dict) => {\n if (!dict.filePath) return false;\n\n return gitChangedFiles.some((gitFile) => dict.filePath === gitFile);\n });\n }\n }\n\n return result.filter((dict) => !dict.autoFilled);\n};\n\nconst transformUriToAbsolutePath = (\n uri: string,\n filePath: string,\n baseDir: string\n) => {\n if (uri.startsWith('/')) {\n return join(baseDir, uri);\n }\n\n if (uri.startsWith('./')) {\n return join(dirname(filePath), uri);\n }\n\n return filePath;\n};\n\nexport type AutoFillData = {\n localeList: Locales[];\n filePath: string;\n};\n\nconst formatAutoFillData = (\n autoFillOptions: AutoFill,\n localeList: Locales[],\n filePath: string,\n dictionaryKey: string,\n configuration: IntlayerConfig\n): AutoFillData[] => {\n const outputContentDeclarationFile: AutoFillData[] = [];\n\n if (!Boolean(autoFillOptions)) return outputContentDeclarationFile;\n\n if (autoFillOptions === true) {\n // wanted jsonFilePath: /..../src/components/home/index.content.json\n // replace file extension in json\n let jsonFilePath = filePath.replace(extname(filePath), '.json');\n\n // if both filePath jsonFilePath are same path, change it as : /..../src/components/home/index.fill.content.json\n if (filePath === jsonFilePath) {\n jsonFilePath = jsonFilePath.replace(extname(jsonFilePath), '.fill.json');\n }\n\n outputContentDeclarationFile.push({\n localeList,\n filePath: jsonFilePath,\n });\n }\n\n if (typeof autoFillOptions === 'string') {\n if (autoFillOptions.includes('{{locale}}')) {\n const output = localeList.map((locale) => ({\n localeList: [locale],\n filePath: transformUriToAbsolutePath(\n autoFillOptions\n .replace('{{locale}}', locale)\n .replace('{{key}}', dictionaryKey),\n filePath,\n configuration.content.baseDir\n ),\n }));\n\n outputContentDeclarationFile.push(...output);\n } else {\n outputContentDeclarationFile.push({\n localeList,\n filePath: transformUriToAbsolutePath(\n autoFillOptions,\n filePath,\n configuration.content.baseDir\n ),\n });\n }\n\n return outputContentDeclarationFile;\n }\n\n if (typeof autoFillOptions === 'object') {\n const localeList = Object.keys(autoFillOptions).filter(\n (locale) => typeof autoFillOptions[locale] === 'string'\n ) as Locales[];\n\n const output: AutoFillData[] = localeList.map((locale) => ({\n localeList: [locale],\n filePath: transformUriToAbsolutePath(\n autoFillOptions[locale].replace('{{key}}', dictionaryKey),\n filePath,\n configuration.content.baseDir\n ),\n }));\n\n // Group by filePath and merge localeList\n const groupedByFilePath = output.reduce((acc, curr) => {\n const existing = acc.find((item) => item.filePath === curr.filePath);\n if (existing) {\n existing.localeList.push(...curr.localeList);\n } else {\n acc.push(curr);\n }\n return acc;\n }, [] as AutoFillData[]);\n\n outputContentDeclarationFile.push(...groupedByFilePath);\n }\n\n return outputContentDeclarationFile;\n};\n\nconst autoFill = async (\n fullDictionary: Dictionary,\n contentDeclarationFile: Dictionary,\n autoFillOptions: AutoFill,\n outputLocales: Locales[],\n parentLocales: Locales[],\n configuration: IntlayerConfig\n) => {\n let localeList: Locales[] = (\n outputLocales ?? configuration.internationalization.locales\n ).filter((locale) => !parentLocales?.includes(locale));\n\n const filePath = contentDeclarationFile.filePath;\n\n if (!filePath) {\n appLogger('No file path found for dictionary', {\n level: 'error',\n });\n return;\n }\n\n const autoFillData: AutoFillData[] = formatAutoFillData(\n autoFillOptions,\n localeList,\n filePath,\n fullDictionary.key,\n configuration\n );\n\n appLogger(`Auto fill data: ${JSON.stringify(autoFillData, null, 2)}`, {\n level: 'info',\n isVerbose: true,\n });\n\n for await (const output of autoFillData) {\n const reducedDictionary = reduceDictionaryContent(\n fullDictionary,\n contentDeclarationFile\n );\n\n const isPerLocaleDeclarationFile = output.localeList.length === 1;\n\n if (isPerLocaleDeclarationFile) {\n const sourceLocale = output.localeList[0];\n const sourceLocaleContent = getLocalisedContent(\n reducedDictionary as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n await writeContentDeclaration({\n ...fullDictionary,\n locale: sourceLocale,\n autoFilled: true,\n autoFill: undefined,\n content: sourceLocaleContent.content,\n filePath: output.filePath,\n });\n } else {\n const filteredDictionary = filterDictionaryLocales(\n reducedDictionary,\n output.localeList\n );\n\n // write file\n await writeContentDeclaration({\n ...fullDictionary,\n autoFilled: true,\n autoFill: undefined,\n content: filteredDictionary.content,\n filePath: output.filePath,\n });\n }\n }\n};\n\n/**\n * Fill translations based on the provided options.\n */\nexport const fill = async (options: FillOptions): Promise<void> => {\n const configuration = getConfiguration(options.configOptions);\n\n const { defaultLocale, locales } = configuration.internationalization;\n const mode = options.mode ?? 'review';\n const baseLocale = options.sourceLocale ?? defaultLocale;\n\n if (!configuration.editor.clientId && !options.aiOptions?.apiKey) {\n appLogger('AI options or API key not provided. Skipping AI translation.', {\n level: 'error',\n });\n // Potentially handle this case differently, e.g., by using a different translation method or stopping.\n\n return;\n }\n\n appLogger(['Starting fill function with options:', options], {\n level: 'info',\n });\n\n const targetUnmergedDictionaries = await getTargetDictionary(options);\n\n // Determine output locales\n const outputLocalesList: Locales[] = (\n options.outputLocales ? ensureArray(options.outputLocales) : locales\n ).filter((locale) =>\n // If mode is review, translate all locales\n // If mode is complete, translate only the locales that are not the source locale\n mode === 'review' ? true : locale !== baseLocale\n );\n\n const affectedDictionaryKeys = new Set<string>();\n targetUnmergedDictionaries.forEach((dict) => {\n affectedDictionaryKeys.add(dict.key);\n });\n\n appLogger(\n [\n 'Affected dictionary keys for processing:',\n Array.from(affectedDictionaryKeys).join(', '),\n ],\n {\n isVerbose: true,\n }\n );\n\n for (const targetUnmergedDictionary of targetUnmergedDictionaries) {\n const dictionaryKey = targetUnmergedDictionary.key;\n const mainDictionaryToProcess = dictionariesRecord[dictionaryKey];\n const sourceLocale: Locales =\n (targetUnmergedDictionary.locale as Locales) ?? baseLocale;\n\n if (!mainDictionaryToProcess) {\n appLogger(\n `Dictionary with key \"${dictionaryKey}\" not found in dictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n appLogger(\n `Processing content declaration: ${targetUnmergedDictionary.filePath}`,\n {\n isVerbose: true,\n }\n );\n\n const sourceLocaleContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n if (Object.keys(sourceLocaleContent).length === 0) {\n appLogger(\n `No content found for dictionary ${dictionaryKey} in source locale ${sourceLocale}. Skipping translation for this dictionary.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n const result: Dictionary[] = [];\n\n // 5. for each locale to translate (exclude base locale) generate json translations\n for await (const targetLocale of outputLocalesList) {\n appLogger(\n `Preparing translation for ${dictionaryKey} from ${sourceLocale} to ${targetLocale}`,\n {\n isVerbose: true,\n }\n );\n\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n targetLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n try {\n const translationResult = await getAiAPI().translateJSON({\n entryFileContent: sourceLocaleContent.content, // Should be JSON, ensure getLocalisedContent provides this.\n presetOutputContent: presetOutputContent.content, // Should be JSON\n dictionaryDescription: mainDictionaryToProcess.description,\n entryLocale: sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions: options.aiOptions,\n });\n\n if (!translationResult.data?.fileContent) {\n appLogger(\n `No content result found for ${dictionaryKey} to ${targetLocale}`,\n {\n level: 'error',\n }\n );\n continue;\n }\n\n const processedPerLocaleDictionary = processPerLocaleDictionary({\n ...mainDictionaryToProcess,\n content: translationResult.data?.fileContent,\n locale: targetLocale,\n });\n\n result.push(processedPerLocaleDictionary);\n } catch (error) {\n appLogger(\n `Error filling ${dictionaryKey} to ${targetLocale}:` + error,\n {\n level: 'error',\n }\n );\n }\n }\n\n const dictionaryToMerge =\n mode === 'review'\n ? [...result, mainDictionaryToProcess] // Mode review: generated content will override the base one\n : [mainDictionaryToProcess, ...result]; // Mode complete: base content will override the generated one\n\n const mergedResults = mergeDictionaries(dictionaryToMerge);\n\n let formattedDict = targetUnmergedDictionary;\n\n if (formattedDict.locale) {\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n formattedDict.locale,\n { dictionaryKey, keyPath: [] }\n );\n formattedDict = {\n ...formattedDict,\n content: presetOutputContent.content,\n };\n }\n\n const reducedResult = reduceDictionaryContent(mergedResults, formattedDict);\n\n await writeContentDeclaration(\n { ...formattedDict, content: reducedResult.content },\n configuration,\n formattedDict.filePath\n );\n\n await autoFill(\n mergedResults,\n targetUnmergedDictionary,\n formattedDict.autoFill,\n outputLocalesList,\n [sourceLocale],\n configuration\n );\n }\n};\n"],"mappings":"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","names":["unmergedDictionariesRecord","localeList","dictionariesRecord"]}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -15,21 +15,21 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
15
15
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
16
16
|
var index_exports = {};
|
|
17
17
|
module.exports = __toCommonJS(index_exports);
|
|
18
|
-
__reExport(index_exports, require('./cli.cjs'), module.exports);
|
|
19
18
|
__reExport(index_exports, require('./build.cjs'), module.exports);
|
|
19
|
+
__reExport(index_exports, require('./cli.cjs'), module.exports);
|
|
20
|
+
__reExport(index_exports, require('./fill.cjs'), module.exports);
|
|
21
|
+
__reExport(index_exports, require('./listContentDeclaration.cjs'), module.exports);
|
|
20
22
|
__reExport(index_exports, require('./pull.cjs'), module.exports);
|
|
21
23
|
__reExport(index_exports, require('./push.cjs'), module.exports);
|
|
22
|
-
__reExport(index_exports, require('./listContentDeclaration.cjs'), module.exports);
|
|
23
|
-
__reExport(index_exports, require('./audit.cjs'), module.exports);
|
|
24
24
|
__reExport(index_exports, require('./pushConfig.cjs'), module.exports);
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
|
-
...require('./cli.cjs'),
|
|
28
27
|
...require('./build.cjs'),
|
|
28
|
+
...require('./cli.cjs'),
|
|
29
|
+
...require('./fill.cjs'),
|
|
30
|
+
...require('./listContentDeclaration.cjs'),
|
|
29
31
|
...require('./pull.cjs'),
|
|
30
32
|
...require('./push.cjs'),
|
|
31
|
-
...require('./listContentDeclaration.cjs'),
|
|
32
|
-
...require('./audit.cjs'),
|
|
33
33
|
...require('./pushConfig.cjs')
|
|
34
34
|
});
|
|
35
35
|
//# sourceMappingURL=index.cjs.map
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './build';\nexport * from './cli';\nexport * from './fill';\nexport * from './listContentDeclaration';\nexport * from './pull';\nexport * from './push';\nexport * from './pushConfig';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,oBAAd;AACA,0BAAc,kBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,qCAHd;AAIA,0BAAc,mBAJd;AAKA,0BAAc,mBALd;AAMA,0BAAc,yBANd;","names":[]}
|
|
@@ -37,7 +37,7 @@ var import_fast_glob = __toESM(require("fast-glob"));
|
|
|
37
37
|
const getContentDeclaration = (options) => {
|
|
38
38
|
const {
|
|
39
39
|
content: { watchedFilesPatternWithPath }
|
|
40
|
-
} = (0, import_config.getConfiguration)(options);
|
|
40
|
+
} = (0, import_config.getConfiguration)(options?.configOptions);
|
|
41
41
|
const contentDeclarationFilesPath = import_fast_glob.default.sync(
|
|
42
42
|
watchedFilesPatternWithPath,
|
|
43
43
|
{
|
|
@@ -47,12 +47,8 @@ const getContentDeclaration = (options) => {
|
|
|
47
47
|
return contentDeclarationFilesPath;
|
|
48
48
|
};
|
|
49
49
|
const listContentDeclaration = (options) => {
|
|
50
|
-
const contentDeclarationFilesPath = getContentDeclaration();
|
|
51
|
-
(0, import_config.
|
|
52
|
-
config: {
|
|
53
|
-
prefix: options?.logPrefix
|
|
54
|
-
}
|
|
55
|
-
});
|
|
50
|
+
const contentDeclarationFilesPath = getContentDeclaration(options);
|
|
51
|
+
(0, import_config.appLogger)(`Content declaration files: ${contentDeclarationFilesPath}`);
|
|
56
52
|
};
|
|
57
53
|
// Annotate the CommonJS export names for ESM import in node:
|
|
58
54
|
0 && (module.exports = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/listContentDeclaration.ts"],"sourcesContent":["import {\n getConfiguration,\n type GetConfigurationOptions,\n
|
|
1
|
+
{"version":3,"sources":["../../src/listContentDeclaration.ts"],"sourcesContent":["import {\n appLogger,\n getConfiguration,\n type GetConfigurationOptions,\n} from '@intlayer/config';\nimport fg from 'fast-glob';\n\ntype GetContentDeclarationOptions = {\n exclude?: string[];\n configOptions?: GetConfigurationOptions;\n};\n\nexport const getContentDeclaration = (\n options?: GetContentDeclarationOptions\n): string[] => {\n const {\n content: { watchedFilesPatternWithPath },\n } = getConfiguration(options?.configOptions);\n\n const contentDeclarationFilesPath: string[] = fg.sync(\n watchedFilesPatternWithPath,\n {\n ignore: options?.exclude,\n }\n );\n\n return contentDeclarationFilesPath;\n};\n\ntype ListContentDeclarationOptions = {\n configOptions?: GetConfigurationOptions;\n};\n\nexport const listContentDeclaration = (\n options?: ListContentDeclarationOptions\n) => {\n const contentDeclarationFilesPath = getContentDeclaration(options);\n\n appLogger(`Content declaration files: ${contentDeclarationFilesPath}`);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAIO;AACP,uBAAe;AAOR,MAAM,wBAAwB,CACnC,YACa;AACb,QAAM;AAAA,IACJ,SAAS,EAAE,4BAA4B;AAAA,EACzC,QAAI,gCAAiB,SAAS,aAAa;AAE3C,QAAM,8BAAwC,iBAAAA,QAAG;AAAA,IAC/C;AAAA,IACA;AAAA,MACE,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAMO,MAAM,yBAAyB,CACpC,YACG;AACH,QAAM,8BAA8B,sBAAsB,OAAO;AAEjE,+BAAU,8BAA8B,2BAA2B,EAAE;AACvE;","names":["fg"]}
|
package/dist/cjs/pull.cjs
CHANGED
|
@@ -31,11 +31,11 @@ __export(pull_exports, {
|
|
|
31
31
|
pull: () => pull
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(pull_exports);
|
|
34
|
-
var readline = __toESM(require("readline"));
|
|
35
34
|
var import_api = require("@intlayer/api");
|
|
36
|
-
var import_config = require("@intlayer/config");
|
|
37
35
|
var import_chokidar = require("@intlayer/chokidar");
|
|
36
|
+
var import_config = require("@intlayer/config");
|
|
38
37
|
var import_p_limit = __toESM(require("p-limit"));
|
|
38
|
+
var readline = __toESM(require("readline"));
|
|
39
39
|
const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
40
40
|
const RESET = "\x1B[0m";
|
|
41
41
|
const GREEN = "\x1B[32m";
|
|
@@ -46,7 +46,7 @@ const YELLOW = "\x1B[33m";
|
|
|
46
46
|
const GREY_DARK = "\x1B[90m";
|
|
47
47
|
const pull = async (options) => {
|
|
48
48
|
try {
|
|
49
|
-
const config = (0, import_config.getConfiguration)(options);
|
|
49
|
+
const config = (0, import_config.getConfiguration)(options?.configOptions);
|
|
50
50
|
const { clientId, clientSecret } = config.editor;
|
|
51
51
|
if (!clientId || !clientSecret) {
|
|
52
52
|
throw new Error(
|
package/dist/cjs/pull.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport {\n getConfiguration,\n GetConfigurationOptions,\n logger,\n} from '@intlayer/config';\nimport type { Dictionary } from '@intlayer/core';\nimport {\n writeContentDeclaration,\n type DictionaryStatus,\n} from '@intlayer/chokidar';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n} & GetConfigurationOptions;\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 try {\n const config = getConfiguration(options);\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n logger('No dictionaries to fetch', {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n return;\n }\n\n logger('Fetching dictionaries:', {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n }\n } catch (error) {\n logger(error, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":["pLimit"]}
|
|
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 getConfiguration,\n GetConfigurationOptions,\n logger,\n} from '@intlayer/config';\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 logPrefix?: 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 try {\n const config = getConfiguration(options?.configOptions);\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n logger('No dictionaries to fetch', {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n return;\n }\n\n logger('Fetching dictionaries:', {\n config: {\n prefix: options?.logPrefix,\n },\n });\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n }\n } catch (error) {\n logger(error, {\n level: 'error',\n config: {\n prefix: options?.logPrefix,\n },\n });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":["pLimit"]}
|