@intlayer/cli 4.0.3 → 4.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/pull.cjs +13 -77
- package/dist/cjs/pull.cjs.map +1 -1
- package/dist/cjs/push.cjs +5 -3
- package/dist/cjs/push.cjs.map +1 -1
- package/dist/esm/audit.mjs +1 -1
- package/dist/esm/cli.mjs +6 -6
- package/dist/esm/index.mjs +6 -6
- package/dist/esm/pull.mjs +11 -75
- package/dist/esm/pull.mjs.map +1 -1
- package/dist/esm/push.mjs +4 -2
- package/dist/esm/push.mjs.map +1 -1
- package/dist/types/pull.d.ts.map +1 -1
- package/dist/types/push.d.ts.map +1 -1
- package/package.json +13 -13
package/dist/cjs/pull.cjs
CHANGED
|
@@ -31,14 +31,10 @@ __export(pull_exports, {
|
|
|
31
31
|
pull: () => pull
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(pull_exports);
|
|
34
|
-
var import_fs = require("fs");
|
|
35
|
-
var fsPromises = __toESM(require("fs/promises"));
|
|
36
|
-
var import_path = require("path");
|
|
37
34
|
var readline = __toESM(require("readline"));
|
|
38
35
|
var import_api = require("@intlayer/api");
|
|
39
36
|
var import_config = require("@intlayer/config");
|
|
40
|
-
var
|
|
41
|
-
var import_lodash = __toESM(require("lodash"));
|
|
37
|
+
var import_server = require("@intlayer/editor/server");
|
|
42
38
|
var import_p_limit = __toESM(require("p-limit"));
|
|
43
39
|
const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
44
40
|
const RESET = "\x1B[0m";
|
|
@@ -48,20 +44,19 @@ const BLUE = "\x1B[34m";
|
|
|
48
44
|
const GREY = "\x1B[90m";
|
|
49
45
|
const YELLOW = "\x1B[33m";
|
|
50
46
|
const GREY_DARK = "\x1B[90m";
|
|
51
|
-
const DEFAULT_NEW_DICTIONARY_PATH = "intlayer-dictionaries";
|
|
52
47
|
const pull = async (options) => {
|
|
53
48
|
try {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
} = (0, import_config.getConfiguration)();
|
|
49
|
+
const config = (0, import_config.getConfiguration)();
|
|
50
|
+
const { clientId, clientSecret } = config.editor;
|
|
57
51
|
if (!clientId || !clientSecret) {
|
|
58
52
|
throw new Error(
|
|
59
53
|
"Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
|
|
60
54
|
);
|
|
61
55
|
}
|
|
62
|
-
const
|
|
56
|
+
const intlayerAPI = (0, import_api.getIntlayerAPI)(void 0, config);
|
|
57
|
+
const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();
|
|
63
58
|
const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
64
|
-
const getDictionariesKeysResult = await
|
|
59
|
+
const getDictionariesKeysResult = await intlayerAPI.dictionary.getDictionariesKeys({
|
|
65
60
|
headers: { Authorization: `Bearer ${oAuth2AccessToken}` }
|
|
66
61
|
});
|
|
67
62
|
if (!getDictionariesKeysResult.data) {
|
|
@@ -96,7 +91,7 @@ const pull = async (options) => {
|
|
|
96
91
|
const processDictionary = async (statusObj) => {
|
|
97
92
|
statusObj.status = "fetching";
|
|
98
93
|
try {
|
|
99
|
-
const getDictionaryResult = await
|
|
94
|
+
const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(
|
|
100
95
|
statusObj.dictionaryKey,
|
|
101
96
|
void 0,
|
|
102
97
|
{
|
|
@@ -109,8 +104,12 @@ const pull = async (options) => {
|
|
|
109
104
|
`Dictionary ${statusObj.dictionaryKey} not found on remote`
|
|
110
105
|
);
|
|
111
106
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
107
|
+
const { status } = await (0, import_server.writeContentDeclaration)(
|
|
108
|
+
distantDictionary,
|
|
109
|
+
config,
|
|
110
|
+
options?.newDictionariesPath
|
|
111
|
+
);
|
|
112
|
+
statusObj.status = status;
|
|
114
113
|
successfullyFetchedDictionaries.push(distantDictionary);
|
|
115
114
|
} catch (error) {
|
|
116
115
|
statusObj.status = "error";
|
|
@@ -146,9 +145,6 @@ const getStatusIcon = (status) => {
|
|
|
146
145
|
return statusIcons[status] ?? "";
|
|
147
146
|
};
|
|
148
147
|
const getStatusLine = (statusObj) => {
|
|
149
|
-
const {
|
|
150
|
-
log: { prefix }
|
|
151
|
-
} = (0, import_config.getConfiguration)();
|
|
152
148
|
let icon = getStatusIcon(statusObj.status);
|
|
153
149
|
let colorStart = "";
|
|
154
150
|
let colorEnd = "";
|
|
@@ -181,66 +177,6 @@ const updateAllStatusLines = (dictionariesStatuses) => {
|
|
|
181
177
|
process.stdout.write(getStatusLine(statusObj) + "\n");
|
|
182
178
|
}
|
|
183
179
|
};
|
|
184
|
-
const writeDictionary = async (distantDictionary, options) => {
|
|
185
|
-
const {
|
|
186
|
-
content: { baseDir }
|
|
187
|
-
} = (0, import_config.getConfiguration)();
|
|
188
|
-
const newDictionaryRelativeLocationPath = options?.newDictionariesPath ?? DEFAULT_NEW_DICTIONARY_PATH;
|
|
189
|
-
const newDictionaryLocationPath = `${baseDir}/${newDictionaryRelativeLocationPath}`;
|
|
190
|
-
const existingDictionary = import_dictionaries_entry.default[distantDictionary.key];
|
|
191
|
-
if (existingDictionary) {
|
|
192
|
-
const { filePath } = existingDictionary;
|
|
193
|
-
if (import_lodash.default.isEqual(existingDictionary, distantDictionary)) {
|
|
194
|
-
return "up-to-date";
|
|
195
|
-
} else {
|
|
196
|
-
if (filePath) {
|
|
197
|
-
const isDictionaryJSON = filePath.endsWith(".json");
|
|
198
|
-
if (isDictionaryJSON) {
|
|
199
|
-
await fsPromises.writeFile(
|
|
200
|
-
`${baseDir}/${filePath}`,
|
|
201
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
202
|
-
);
|
|
203
|
-
return "updated";
|
|
204
|
-
} else {
|
|
205
|
-
const dictionariesDirPath = (0, import_path.dirname)(filePath);
|
|
206
|
-
const dictionariesFileName = (0, import_path.basename)(filePath, (0, import_path.extname)(filePath));
|
|
207
|
-
const newFilePath = `${dictionariesDirPath}/${dictionariesFileName}.json`;
|
|
208
|
-
await writeFileWithDirectories(
|
|
209
|
-
newFilePath,
|
|
210
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
211
|
-
);
|
|
212
|
-
return "reimported in JSON";
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;
|
|
216
|
-
await writeFileWithDirectories(
|
|
217
|
-
dictionaryPath,
|
|
218
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
219
|
-
);
|
|
220
|
-
return "reimported in new location";
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
} else {
|
|
224
|
-
const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;
|
|
225
|
-
await writeFileWithDirectories(
|
|
226
|
-
dictionaryPath,
|
|
227
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
228
|
-
);
|
|
229
|
-
return "imported";
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
const writeFileWithDirectories = async (filePath, data) => {
|
|
233
|
-
try {
|
|
234
|
-
const dir = (0, import_path.dirname)(filePath);
|
|
235
|
-
const directoryExists = (0, import_fs.existsSync)(dir);
|
|
236
|
-
if (!directoryExists) {
|
|
237
|
-
await fsPromises.mkdir(dir, { recursive: true });
|
|
238
|
-
}
|
|
239
|
-
await fsPromises.writeFile(filePath, data);
|
|
240
|
-
} catch (error) {
|
|
241
|
-
throw new Error(`Error writing file to ${filePath}: ${error}`);
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
180
|
// Annotate the CommonJS export names for ESM import in node:
|
|
245
181
|
0 && (module.exports = {
|
|
246
182
|
pull
|
package/dist/cjs/pull.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport * as fsPromises from 'fs/promises';\nimport { basename, dirname, extname } from 'path';\nimport * as readline from 'readline';\nimport { intlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport _ from 'lodash';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status:\n | 'pending'\n | 'fetching'\n | 'up-to-date'\n | 'updated'\n | 'fetched'\n | 'unknown'\n | 'error'\n | 'imported'\n | 'reimported in JSON'\n | 'reimported in new location';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\nconst DEFAULT_NEW_DICTIONARY_PATH = 'intlayer-dictionaries';\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 {\n editor: { clientId, clientSecret },\n } = getConfiguration();\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 oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n logger('No dictionaries to fetch', { level: 'error' });\n return;\n }\n\n logger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const writeStatus = await writeDictionary(distantDictionary, options);\n\n statusObj.status = writeStatus;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\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\nconst writeDictionary = async (\n distantDictionary: Dictionary,\n options?: PullOptions\n): Promise<DictionariesStatus['status']> => {\n const {\n content: { baseDir },\n } = getConfiguration();\n\n const newDictionaryRelativeLocationPath =\n options?.newDictionariesPath ?? DEFAULT_NEW_DICTIONARY_PATH;\n const newDictionaryLocationPath = `${baseDir}/${newDictionaryRelativeLocationPath}`;\n\n const existingDictionary = dictionariesRecord[distantDictionary.key];\n\n if (existingDictionary) {\n const { filePath } = existingDictionary;\n\n // Compare existing dictionary with distant dictionary\n if (_.isEqual(existingDictionary, distantDictionary)) {\n // Up to date, nothing to do\n return 'up-to-date';\n } else {\n if (filePath) {\n const isDictionaryJSON = filePath.endsWith('.json');\n\n if (isDictionaryJSON) {\n // Write the dictionary to the same location of the existing dictionary file\n await fsPromises.writeFile(\n `${baseDir}/${filePath}`,\n JSON.stringify(distantDictionary, null, 2)\n );\n return 'updated';\n } else {\n // Write the dictionary to the intlayer-dictionaries directory\n const dictionariesDirPath = dirname(filePath);\n const dictionariesFileName = basename(filePath, extname(filePath));\n\n const newFilePath = `${dictionariesDirPath}/${dictionariesFileName}.json`;\n\n await writeFileWithDirectories(\n newFilePath,\n JSON.stringify(distantDictionary, null, 2)\n );\n return 'reimported in JSON';\n }\n } else {\n // Write the dictionary to the intlayer-dictionaries directory\n const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;\n await writeFileWithDirectories(\n dictionaryPath,\n JSON.stringify(distantDictionary, null, 2)\n );\n return 'reimported in new location';\n }\n }\n } else {\n // No existing dictionary, write to new location\n const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;\n\n await writeFileWithDirectories(\n dictionaryPath,\n JSON.stringify(distantDictionary, null, 2)\n );\n\n return 'imported';\n }\n};\n\nconst writeFileWithDirectories = async (\n filePath: string,\n data: string | Buffer\n): Promise<void> => {\n try {\n // Extract the directory from the file path\n const dir = dirname(filePath);\n\n // Check if the directory exists\n const directoryExists = existsSync(dir);\n\n if (!directoryExists) {\n // Create the directory recursively\n await fsPromises.mkdir(dir, { recursive: true });\n }\n\n // Write the file\n await fsPromises.writeFile(filePath, data);\n } catch (error) {\n throw new Error(`Error writing file to ${filePath}: ${error}`);\n }\n};\n"],"mappings":"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","names":["pLimit","dictionariesRecord","_"]}
|
|
1
|
+
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport { writeContentDeclaration } from '@intlayer/editor/server';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status:\n | 'pending'\n | 'fetching'\n | 'up-to-date'\n | 'updated'\n | 'fetched'\n | 'unknown'\n | 'error'\n | 'imported'\n | 'reimported in JSON'\n | 'reimported in new location';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n try {\n const config = getConfiguration();\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n logger('No dictionaries to fetch', { level: 'error' });\n return;\n }\n\n logger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":["pLimit"]}
|
package/dist/cjs/push.cjs
CHANGED
|
@@ -47,13 +47,15 @@ const GREY = "\x1B[90m";
|
|
|
47
47
|
const GREY_DARK = "\x1B[90m";
|
|
48
48
|
const push = async (options) => {
|
|
49
49
|
try {
|
|
50
|
-
const
|
|
50
|
+
const config = (0, import_config.getConfiguration)();
|
|
51
|
+
const { clientId, clientSecret } = config.editor;
|
|
51
52
|
if (!clientId || !clientSecret) {
|
|
52
53
|
throw new Error(
|
|
53
54
|
"Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
|
|
54
55
|
);
|
|
55
56
|
}
|
|
56
|
-
const
|
|
57
|
+
const intlayerAPI = (0, import_api.getIntlayerAPI)(void 0, config);
|
|
58
|
+
const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();
|
|
57
59
|
const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
58
60
|
let dictionaries = Object.values(import_dictionaries_entry.default);
|
|
59
61
|
const existingDictionariesKeys = Object.keys(import_dictionaries_entry.default);
|
|
@@ -97,7 +99,7 @@ const push = async (options) => {
|
|
|
97
99
|
const processDictionary = async (statusObj) => {
|
|
98
100
|
statusObj.status = "pushing";
|
|
99
101
|
try {
|
|
100
|
-
const pushResult = await
|
|
102
|
+
const pushResult = await intlayerAPI.dictionary.pushDictionaries(
|
|
101
103
|
[statusObj.dictionary],
|
|
102
104
|
{
|
|
103
105
|
headers: {
|
package/dist/cjs/push.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import * as fsPromises from 'fs/promises';\nimport { relative } from 'path';\nimport * as readline from 'readline';\nimport { intlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Get all locale dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n try {\n const { clientId, clientSecret } = getConfiguration().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 oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n let dictionaries: Dictionary[] = Object.values(dictionariesRecord);\n const existingDictionariesKeys: string[] = Object.keys(dictionariesRecord);\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n logger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n { level: 'error' }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries!.includes(dictionary.key)\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n logger('No local dictionaries found', { level: 'error' });\n return;\n }\n\n logger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary, index) => ({\n dictionary,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n })\n );\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries(\n [statusObj.dictionary],\n {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }\n );\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries || [];\n const newDictionaries = pushResult.data?.newDictionaries || [];\n\n if (updatedDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n const pushPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n await Promise.all(pushPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const answer = await askUser(\n 'Do you want to delete the local dictionaries that were successfully pushed? (yes/no): '\n );\n if (answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') {\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst askUser = (question: string): Promise<string> => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer: string) => {\n rl.close();\n resolve(answer);\n });\n });\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[]\n): Promise<void> => {\n const { baseDir } = getConfiguration().content;\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n logger(`Dictionary ${dictionary.key} does not have a file path`, {\n level: 'error',\n });\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n const relativePath = relative(baseDir, filePath);\n\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n logger(`Deleted file ${relativePath}`);\n } else if (stats.isDirectory()) {\n logger(`Path is a directory ${relativePath}, skipping.`);\n } else {\n logger(`Unknown file type for ${relativePath}, skipping.`);\n }\n } catch (err) {\n logger(`Error deleting ${relativePath}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n pushing: '', // Spinner handled separately\n modified: '✔',\n pushed: '✔',\n error: '✖',\n };\n return statusIcons[status] || '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'pushing') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = GREEN;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'pushing') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":["dictionariesRecord","pLimit"]}
|
|
1
|
+
{"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import * as fsPromises from 'fs/promises';\nimport { relative } from 'path';\nimport * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Get all locale dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n try {\n const config = getConfiguration();\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n let dictionaries: Dictionary[] = Object.values(dictionariesRecord);\n const existingDictionariesKeys: string[] = Object.keys(dictionariesRecord);\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n logger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n { level: 'error' }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries!.includes(dictionary.key)\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n logger('No local dictionaries found', { level: 'error' });\n return;\n }\n\n logger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary, index) => ({\n dictionary,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n })\n );\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries(\n [statusObj.dictionary],\n {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }\n );\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries || [];\n const newDictionaries = pushResult.data?.newDictionaries || [];\n\n if (updatedDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n const pushPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n await Promise.all(pushPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const answer = await askUser(\n 'Do you want to delete the local dictionaries that were successfully pushed? (yes/no): '\n );\n if (answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') {\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst askUser = (question: string): Promise<string> => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer: string) => {\n rl.close();\n resolve(answer);\n });\n });\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[]\n): Promise<void> => {\n const { baseDir } = getConfiguration().content;\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n logger(`Dictionary ${dictionary.key} does not have a file path`, {\n level: 'error',\n });\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n const relativePath = relative(baseDir, filePath);\n\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n logger(`Deleted file ${relativePath}`);\n } else if (stats.isDirectory()) {\n logger(`Path is a directory ${relativePath}, skipping.`);\n } else {\n logger(`Unknown file type for ${relativePath}, skipping.`);\n }\n } catch (err) {\n logger(`Error deleting ${relativePath}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n pushing: '', // Spinner handled separately\n modified: '✔',\n pushed: '✔',\n error: '✖',\n };\n return statusIcons[status] || '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'pushing') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = GREEN;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'pushing') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":["dictionariesRecord","pLimit"]}
|
package/dist/esm/audit.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { join, relative } from "path";
|
|
|
3
3
|
import { intlayerAPI } from "@intlayer/api";
|
|
4
4
|
import { getConfiguration, logger } from "@intlayer/config";
|
|
5
5
|
import pLimit from "p-limit";
|
|
6
|
-
import { getContentDeclaration } from
|
|
6
|
+
import { getContentDeclaration } from "./listContentDeclaration.mjs";
|
|
7
7
|
const projectPath = process.cwd();
|
|
8
8
|
const auditFile = async (filePath, options) => {
|
|
9
9
|
try {
|
package/dist/esm/cli.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { audit } from
|
|
3
|
-
import { build } from
|
|
4
|
-
import { getConfig } from
|
|
5
|
-
import { listContentDeclaration } from
|
|
6
|
-
import { pull } from
|
|
7
|
-
import { push } from
|
|
2
|
+
import { audit } from "./audit.mjs";
|
|
3
|
+
import { build } from "./build.mjs";
|
|
4
|
+
import { getConfig } from "./config.mjs";
|
|
5
|
+
import { listContentDeclaration } from "./listContentDeclaration.mjs";
|
|
6
|
+
import { pull } from "./pull.mjs";
|
|
7
|
+
import { push } from "./push.mjs";
|
|
8
8
|
const setAPI = () => {
|
|
9
9
|
const program = new Command();
|
|
10
10
|
program.version("1.0.0").description("Intlayer CLI");
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
1
|
+
export * from "./cli.mjs";
|
|
2
|
+
export * from "./build.mjs";
|
|
3
|
+
export * from "./pull.mjs";
|
|
4
|
+
export * from "./push.mjs";
|
|
5
|
+
export * from "./listContentDeclaration.mjs";
|
|
6
|
+
export * from "./audit.mjs";
|
|
7
7
|
//# sourceMappingURL=index.mjs.map
|
package/dist/esm/pull.mjs
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { existsSync } from "fs";
|
|
2
|
-
import * as fsPromises from "fs/promises";
|
|
3
|
-
import { basename, dirname, extname } from "path";
|
|
4
1
|
import * as readline from "readline";
|
|
5
|
-
import {
|
|
2
|
+
import { getIntlayerAPI } from "@intlayer/api";
|
|
6
3
|
import { getConfiguration, logger } from "@intlayer/config";
|
|
7
|
-
import
|
|
8
|
-
import _ from "lodash";
|
|
4
|
+
import { writeContentDeclaration } from "@intlayer/editor/server";
|
|
9
5
|
import pLimit from "p-limit";
|
|
10
6
|
const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
11
7
|
const RESET = "\x1B[0m";
|
|
@@ -15,17 +11,16 @@ const BLUE = "\x1B[34m";
|
|
|
15
11
|
const GREY = "\x1B[90m";
|
|
16
12
|
const YELLOW = "\x1B[33m";
|
|
17
13
|
const GREY_DARK = "\x1B[90m";
|
|
18
|
-
const DEFAULT_NEW_DICTIONARY_PATH = "intlayer-dictionaries";
|
|
19
14
|
const pull = async (options) => {
|
|
20
15
|
try {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
} = getConfiguration();
|
|
16
|
+
const config = getConfiguration();
|
|
17
|
+
const { clientId, clientSecret } = config.editor;
|
|
24
18
|
if (!clientId || !clientSecret) {
|
|
25
19
|
throw new Error(
|
|
26
20
|
"Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
|
|
27
21
|
);
|
|
28
22
|
}
|
|
23
|
+
const intlayerAPI = getIntlayerAPI(void 0, config);
|
|
29
24
|
const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();
|
|
30
25
|
const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
31
26
|
const getDictionariesKeysResult = await intlayerAPI.dictionary.getDictionariesKeys({
|
|
@@ -76,8 +71,12 @@ const pull = async (options) => {
|
|
|
76
71
|
`Dictionary ${statusObj.dictionaryKey} not found on remote`
|
|
77
72
|
);
|
|
78
73
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
74
|
+
const { status } = await writeContentDeclaration(
|
|
75
|
+
distantDictionary,
|
|
76
|
+
config,
|
|
77
|
+
options?.newDictionariesPath
|
|
78
|
+
);
|
|
79
|
+
statusObj.status = status;
|
|
81
80
|
successfullyFetchedDictionaries.push(distantDictionary);
|
|
82
81
|
} catch (error) {
|
|
83
82
|
statusObj.status = "error";
|
|
@@ -113,9 +112,6 @@ const getStatusIcon = (status) => {
|
|
|
113
112
|
return statusIcons[status] ?? "";
|
|
114
113
|
};
|
|
115
114
|
const getStatusLine = (statusObj) => {
|
|
116
|
-
const {
|
|
117
|
-
log: { prefix }
|
|
118
|
-
} = getConfiguration();
|
|
119
115
|
let icon = getStatusIcon(statusObj.status);
|
|
120
116
|
let colorStart = "";
|
|
121
117
|
let colorEnd = "";
|
|
@@ -148,66 +144,6 @@ const updateAllStatusLines = (dictionariesStatuses) => {
|
|
|
148
144
|
process.stdout.write(getStatusLine(statusObj) + "\n");
|
|
149
145
|
}
|
|
150
146
|
};
|
|
151
|
-
const writeDictionary = async (distantDictionary, options) => {
|
|
152
|
-
const {
|
|
153
|
-
content: { baseDir }
|
|
154
|
-
} = getConfiguration();
|
|
155
|
-
const newDictionaryRelativeLocationPath = options?.newDictionariesPath ?? DEFAULT_NEW_DICTIONARY_PATH;
|
|
156
|
-
const newDictionaryLocationPath = `${baseDir}/${newDictionaryRelativeLocationPath}`;
|
|
157
|
-
const existingDictionary = dictionariesRecord[distantDictionary.key];
|
|
158
|
-
if (existingDictionary) {
|
|
159
|
-
const { filePath } = existingDictionary;
|
|
160
|
-
if (_.isEqual(existingDictionary, distantDictionary)) {
|
|
161
|
-
return "up-to-date";
|
|
162
|
-
} else {
|
|
163
|
-
if (filePath) {
|
|
164
|
-
const isDictionaryJSON = filePath.endsWith(".json");
|
|
165
|
-
if (isDictionaryJSON) {
|
|
166
|
-
await fsPromises.writeFile(
|
|
167
|
-
`${baseDir}/${filePath}`,
|
|
168
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
169
|
-
);
|
|
170
|
-
return "updated";
|
|
171
|
-
} else {
|
|
172
|
-
const dictionariesDirPath = dirname(filePath);
|
|
173
|
-
const dictionariesFileName = basename(filePath, extname(filePath));
|
|
174
|
-
const newFilePath = `${dictionariesDirPath}/${dictionariesFileName}.json`;
|
|
175
|
-
await writeFileWithDirectories(
|
|
176
|
-
newFilePath,
|
|
177
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
178
|
-
);
|
|
179
|
-
return "reimported in JSON";
|
|
180
|
-
}
|
|
181
|
-
} else {
|
|
182
|
-
const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;
|
|
183
|
-
await writeFileWithDirectories(
|
|
184
|
-
dictionaryPath,
|
|
185
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
186
|
-
);
|
|
187
|
-
return "reimported in new location";
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
} else {
|
|
191
|
-
const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;
|
|
192
|
-
await writeFileWithDirectories(
|
|
193
|
-
dictionaryPath,
|
|
194
|
-
JSON.stringify(distantDictionary, null, 2)
|
|
195
|
-
);
|
|
196
|
-
return "imported";
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
const writeFileWithDirectories = async (filePath, data) => {
|
|
200
|
-
try {
|
|
201
|
-
const dir = dirname(filePath);
|
|
202
|
-
const directoryExists = existsSync(dir);
|
|
203
|
-
if (!directoryExists) {
|
|
204
|
-
await fsPromises.mkdir(dir, { recursive: true });
|
|
205
|
-
}
|
|
206
|
-
await fsPromises.writeFile(filePath, data);
|
|
207
|
-
} catch (error) {
|
|
208
|
-
throw new Error(`Error writing file to ${filePath}: ${error}`);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
147
|
export {
|
|
212
148
|
pull
|
|
213
149
|
};
|
package/dist/esm/pull.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport * as fsPromises from 'fs/promises';\nimport { basename, dirname, extname } from 'path';\nimport * as readline from 'readline';\nimport { intlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport _ from 'lodash';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status:\n | 'pending'\n | 'fetching'\n | 'up-to-date'\n | 'updated'\n | 'fetched'\n | 'unknown'\n | 'error'\n | 'imported'\n | 'reimported in JSON'\n | 'reimported in new location';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\nconst DEFAULT_NEW_DICTIONARY_PATH = 'intlayer-dictionaries';\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 {\n editor: { clientId, clientSecret },\n } = getConfiguration();\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 oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n logger('No dictionaries to fetch', { level: 'error' });\n return;\n }\n\n logger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const writeStatus = await writeDictionary(distantDictionary, options);\n\n statusObj.status = writeStatus;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\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\nconst writeDictionary = async (\n distantDictionary: Dictionary,\n options?: PullOptions\n): Promise<DictionariesStatus['status']> => {\n const {\n content: { baseDir },\n } = getConfiguration();\n\n const newDictionaryRelativeLocationPath =\n options?.newDictionariesPath ?? DEFAULT_NEW_DICTIONARY_PATH;\n const newDictionaryLocationPath = `${baseDir}/${newDictionaryRelativeLocationPath}`;\n\n const existingDictionary = dictionariesRecord[distantDictionary.key];\n\n if (existingDictionary) {\n const { filePath } = existingDictionary;\n\n // Compare existing dictionary with distant dictionary\n if (_.isEqual(existingDictionary, distantDictionary)) {\n // Up to date, nothing to do\n return 'up-to-date';\n } else {\n if (filePath) {\n const isDictionaryJSON = filePath.endsWith('.json');\n\n if (isDictionaryJSON) {\n // Write the dictionary to the same location of the existing dictionary file\n await fsPromises.writeFile(\n `${baseDir}/${filePath}`,\n JSON.stringify(distantDictionary, null, 2)\n );\n return 'updated';\n } else {\n // Write the dictionary to the intlayer-dictionaries directory\n const dictionariesDirPath = dirname(filePath);\n const dictionariesFileName = basename(filePath, extname(filePath));\n\n const newFilePath = `${dictionariesDirPath}/${dictionariesFileName}.json`;\n\n await writeFileWithDirectories(\n newFilePath,\n JSON.stringify(distantDictionary, null, 2)\n );\n return 'reimported in JSON';\n }\n } else {\n // Write the dictionary to the intlayer-dictionaries directory\n const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;\n await writeFileWithDirectories(\n dictionaryPath,\n JSON.stringify(distantDictionary, null, 2)\n );\n return 'reimported in new location';\n }\n }\n } else {\n // No existing dictionary, write to new location\n const dictionaryPath = `${newDictionaryLocationPath}/${distantDictionary.key}.content.json`;\n\n await writeFileWithDirectories(\n dictionaryPath,\n JSON.stringify(distantDictionary, null, 2)\n );\n\n return 'imported';\n }\n};\n\nconst writeFileWithDirectories = async (\n filePath: string,\n data: string | Buffer\n): Promise<void> => {\n try {\n // Extract the directory from the file path\n const dir = dirname(filePath);\n\n // Check if the directory exists\n const directoryExists = existsSync(dir);\n\n if (!directoryExists) {\n // Create the directory recursively\n await fsPromises.mkdir(dir, { recursive: true });\n }\n\n // Write the file\n await fsPromises.writeFile(filePath, data);\n } catch (error) {\n throw new Error(`Error writing file to ${filePath}: ${error}`);\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/pull.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport { writeContentDeclaration } from '@intlayer/editor/server';\nimport pLimit from 'p-limit';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n logPrefix?: string;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status:\n | 'pending'\n | 'fetching'\n | 'up-to-date'\n | 'updated'\n | 'fetched'\n | 'unknown'\n | 'error'\n | 'imported'\n | 'reimported in JSON'\n | 'reimported in new location';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst YELLOW = '\\x1b[33m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n try {\n const config = getConfiguration();\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await intlayerAPI.dictionary.getDictionariesKeys({\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n });\n\n if (!getDictionariesKeysResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesKeys: string[] = getDictionariesKeysResult.data;\n\n if (options?.dictionaries) {\n // Filter the dictionaries from the provided list of IDs\n distantDictionariesKeys = distantDictionariesKeys.filter(\n (dictionaryKey) => options.dictionaries!.includes(dictionaryKey)\n );\n }\n\n // Check if dictionaries list is empty\n if (distantDictionariesKeys.length === 0) {\n logger('No dictionaries to fetch', { level: 'error' });\n return;\n }\n\n logger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] =\n distantDictionariesKeys.map((dictionaryKey, index) => ({\n dictionaryKey,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n }));\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'fetching';\n try {\n // Fetch the dictionary\n const getDictionaryResult = await intlayerAPI.dictionary.getDictionary(\n statusObj.dictionaryKey,\n undefined,\n {\n headers: { Authorization: `Bearer ${oAuth2AccessToken}` },\n }\n );\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n distantDictionary,\n config,\n options?.newDictionariesPath\n );\n\n statusObj.status = status;\n\n successfullyFetchedDictionaries.push(distantDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n }\n };\n\n const fetchPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n\n await Promise.all(fetchPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n fetching: '', // Spinner handled separately\n 'up-to-date': '✔',\n updated: '✔',\n fetched: '✔',\n error: '✖',\n };\n return statusIcons[status] ?? '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'fetching') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'fetched' ||\n statusObj.status === 'imported' ||\n statusObj.status === 'updated' ||\n statusObj.status === 'up-to-date'\n ) {\n colorStart = GREEN;\n colorEnd = RESET;\n } else if (\n statusObj.status === 'reimported in JSON' ||\n statusObj.status === 'reimported in new location'\n ) {\n colorStart = YELLOW;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionaryKey} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'fetching') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":[]}
|
package/dist/esm/push.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fsPromises from "fs/promises";
|
|
2
2
|
import { relative } from "path";
|
|
3
3
|
import * as readline from "readline";
|
|
4
|
-
import {
|
|
4
|
+
import { getIntlayerAPI } from "@intlayer/api";
|
|
5
5
|
import { getConfiguration, logger } from "@intlayer/config";
|
|
6
6
|
import dictionariesRecord from "@intlayer/dictionaries-entry";
|
|
7
7
|
import pLimit from "p-limit";
|
|
@@ -14,12 +14,14 @@ const GREY = "\x1B[90m";
|
|
|
14
14
|
const GREY_DARK = "\x1B[90m";
|
|
15
15
|
const push = async (options) => {
|
|
16
16
|
try {
|
|
17
|
-
const
|
|
17
|
+
const config = getConfiguration();
|
|
18
|
+
const { clientId, clientSecret } = config.editor;
|
|
18
19
|
if (!clientId || !clientSecret) {
|
|
19
20
|
throw new Error(
|
|
20
21
|
"Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project."
|
|
21
22
|
);
|
|
22
23
|
}
|
|
24
|
+
const intlayerAPI = getIntlayerAPI(void 0, config);
|
|
23
25
|
const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();
|
|
24
26
|
const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
|
|
25
27
|
let dictionaries = Object.values(dictionariesRecord);
|
package/dist/esm/push.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import * as fsPromises from 'fs/promises';\nimport { relative } from 'path';\nimport * as readline from 'readline';\nimport { intlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Get all locale dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n try {\n const { clientId, clientSecret } = getConfiguration().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 oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n let dictionaries: Dictionary[] = Object.values(dictionariesRecord);\n const existingDictionariesKeys: string[] = Object.keys(dictionariesRecord);\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n logger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n { level: 'error' }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries!.includes(dictionary.key)\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n logger('No local dictionaries found', { level: 'error' });\n return;\n }\n\n logger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary, index) => ({\n dictionary,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n })\n );\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries(\n [statusObj.dictionary],\n {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }\n );\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries || [];\n const newDictionaries = pushResult.data?.newDictionaries || [];\n\n if (updatedDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n const pushPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n await Promise.all(pushPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const answer = await askUser(\n 'Do you want to delete the local dictionaries that were successfully pushed? (yes/no): '\n );\n if (answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') {\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst askUser = (question: string): Promise<string> => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer: string) => {\n rl.close();\n resolve(answer);\n });\n });\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[]\n): Promise<void> => {\n const { baseDir } = getConfiguration().content;\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n logger(`Dictionary ${dictionary.key} does not have a file path`, {\n level: 'error',\n });\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n const relativePath = relative(baseDir, filePath);\n\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n logger(`Deleted file ${relativePath}`);\n } else if (stats.isDirectory()) {\n logger(`Path is a directory ${relativePath}, skipping.`);\n } else {\n logger(`Unknown file type for ${relativePath}, skipping.`);\n }\n } catch (err) {\n logger(`Error deleting ${relativePath}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n pushing: '', // Spinner handled separately\n modified: '✔',\n pushed: '✔',\n error: '✖',\n };\n return statusIcons[status] || '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'pushing') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = GREEN;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'pushing') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/push.ts"],"sourcesContent":["import * as fsPromises from 'fs/promises';\nimport { relative } from 'path';\nimport * as readline from 'readline';\nimport { getIntlayerAPI } from '@intlayer/api';\nimport { getConfiguration, logger } from '@intlayer/config';\nimport { Dictionary } from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status: 'pending' | 'pushing' | 'modified' | 'pushed' | 'unknown' | 'error';\n icon: string;\n index: number;\n error?: Error;\n errorMessage?: string;\n spinnerFrameIndex?: number;\n};\n\nconst spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst RESET = '\\x1b[0m';\nconst GREEN = '\\x1b[32m';\nconst RED = '\\x1b[31m';\nconst BLUE = '\\x1b[34m';\nconst GREY = '\\x1b[90m';\nconst GREY_DARK = '\\x1b[90m';\n\n/**\n * Get all locale dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n try {\n const config = getConfiguration();\n const { clientId, clientSecret } = config.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://intlayer.org/dashboard/project.'\n );\n }\n\n const intlayerAPI = getIntlayerAPI(undefined, config);\n const oAuth2TokenResult = await intlayerAPI.auth.getOAuth2AccessToken();\n\n const oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n\n let dictionaries: Dictionary[] = Object.values(dictionariesRecord);\n const existingDictionariesKeys: string[] = Object.keys(dictionariesRecord);\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n logger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n { level: 'error' }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries!.includes(dictionary.key)\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n logger('No local dictionaries found', { level: 'error' });\n return;\n }\n\n logger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary, index) => ({\n dictionary,\n icon: getStatusIcon('pending'),\n status: 'pending',\n index,\n spinnerFrameIndex: 0,\n })\n );\n\n // Output initial statuses\n for (const statusObj of dictionariesStatuses) {\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n // Start spinner timer\n const spinnerTimer = setInterval(() => {\n updateAllStatusLines(dictionariesStatuses);\n }, 100); // Update every 100ms\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries(\n [statusObj.dictionary],\n {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }\n );\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries || [];\n const newDictionaries = pushResult.data?.newDictionaries || [];\n\n if (updatedDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else if (newDictionaries.includes(statusObj.dictionary.key)) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit\n const limit = pLimit(5); // Limit the number of concurrent requests\n const pushPromises = dictionariesStatuses.map((statusObj) =>\n limit(() => processDictionary(statusObj))\n );\n await Promise.all(pushPromises);\n\n // Stop the spinner timer\n clearInterval(spinnerTimer);\n\n // Update statuses one last time\n updateAllStatusLines(dictionariesStatuses);\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n logger(statusObj.errorMessage, { level: 'error' });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const answer = await askUser(\n 'Do you want to delete the local dictionaries that were successfully pushed? (yes/no): '\n );\n if (answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') {\n await deleteLocalDictionaries(successfullyPushedDictionaries);\n }\n }\n } catch (error) {\n logger(error, { level: 'error' });\n }\n};\n\nconst askUser = (question: string): Promise<string> => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer: string) => {\n rl.close();\n resolve(answer);\n });\n });\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[]\n): Promise<void> => {\n const { baseDir } = getConfiguration().content;\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n logger(`Dictionary ${dictionary.key} does not have a file path`, {\n level: 'error',\n });\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n const relativePath = relative(baseDir, filePath);\n\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n logger(`Deleted file ${relativePath}`);\n } else if (stats.isDirectory()) {\n logger(`Path is a directory ${relativePath}, skipping.`);\n } else {\n logger(`Unknown file type for ${relativePath}, skipping.`);\n }\n } catch (err) {\n logger(`Error deleting ${relativePath}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n\nconst getStatusIcon = (status: string): string => {\n const statusIcons: Record<string, string> = {\n pending: '⏲',\n pushing: '', // Spinner handled separately\n modified: '✔',\n pushed: '✔',\n error: '✖',\n };\n return statusIcons[status] || '';\n};\n\nconst getStatusLine = (statusObj: DictionariesStatus): string => {\n const {\n log: { prefix },\n } = getConfiguration();\n\n let icon = getStatusIcon(statusObj.status);\n let colorStart = '';\n let colorEnd = '';\n\n if (statusObj.status === 'pushing') {\n // Use spinner frame\n icon = spinnerFrames[statusObj.spinnerFrameIndex! % spinnerFrames.length];\n colorStart = BLUE;\n colorEnd = RESET;\n } else if (statusObj.status === 'error') {\n colorStart = RED;\n colorEnd = RESET;\n } else if (statusObj.status === 'pushed' || statusObj.status === 'modified') {\n colorStart = GREEN;\n colorEnd = RESET;\n } else {\n colorStart = GREY;\n colorEnd = RESET;\n }\n\n return `- ${statusObj.dictionary.key} ${GREY_DARK}[${colorStart}${icon}${statusObj.status}${GREY_DARK}]${colorEnd}`;\n};\n\nconst updateAllStatusLines = (dictionariesStatuses: DictionariesStatus[]) => {\n // Move cursor up to the first status line\n readline.moveCursor(process.stdout, 0, -dictionariesStatuses.length);\n for (const statusObj of dictionariesStatuses) {\n // Clear the line\n readline.clearLine(process.stdout, 0);\n\n if (statusObj.status === 'pushing') {\n // Update spinner frame\n statusObj.spinnerFrameIndex =\n (statusObj.spinnerFrameIndex! + 1) % spinnerFrames.length;\n }\n\n // Write the status line\n process.stdout.write(getStatusLine(statusObj) + '\\n');\n }\n};\n"],"mappings":"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","names":[]}
|
package/dist/types/pull.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/pull.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/pull.ts"],"names":[],"mappings":"AAOA,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAgCF;;;GAGG;AACH,eAAO,MAAM,IAAI,aAAoB,WAAW,KAAG,OAAO,CAAC,IAAI,CAiI9D,CAAC"}
|
package/dist/types/push.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/push.ts"],"names":[],"mappings":"AASA,KAAK,WAAW,GAAG;IACjB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAqBF;;GAEG;AACH,eAAO,MAAM,IAAI,aAAoB,WAAW,KAAG,OAAO,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/push.ts"],"names":[],"mappings":"AASA,KAAK,WAAW,GAAG;IACjB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAqBF;;GAEG;AACH,eAAO,MAAM,IAAI,aAAoB,WAAW,KAAG,OAAO,CAAC,IAAI,CAwJ9D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Provides uniform command-line interface scripts for Intlayer, used in packages like intlayer-cli and intlayer.",
|
|
6
6
|
"keywords": [
|
|
@@ -50,15 +50,14 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"commander": "^13.0.0",
|
|
52
52
|
"fast-glob": "^3.3.3",
|
|
53
|
-
"lodash": "^4.17.21",
|
|
54
53
|
"p-limit": "^3.1.0",
|
|
55
|
-
"@intlayer/chokidar": "4.0.
|
|
56
|
-
"@intlayer/
|
|
57
|
-
"@intlayer/
|
|
58
|
-
"@intlayer/
|
|
54
|
+
"@intlayer/chokidar": "4.0.5",
|
|
55
|
+
"@intlayer/config": "4.0.5",
|
|
56
|
+
"@intlayer/api": "4.0.5",
|
|
57
|
+
"@intlayer/editor": "4.0.5",
|
|
58
|
+
"@intlayer/dictionaries-entry": "4.0.5"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@types/lodash": "^4.17.14",
|
|
62
61
|
"@types/node": "^22.10.6",
|
|
63
62
|
"@typescript-eslint/parser": "^8.20.0",
|
|
64
63
|
"concurrently": "^9.1.2",
|
|
@@ -68,17 +67,18 @@
|
|
|
68
67
|
"tsc-alias": "^1.8.10",
|
|
69
68
|
"tsup": "^8.3.5",
|
|
70
69
|
"typescript": "^5.7.3",
|
|
71
|
-
"@intlayer/core": "4.0.
|
|
70
|
+
"@intlayer/core": "4.0.5",
|
|
71
|
+
"@utils/ts-config": "1.0.4",
|
|
72
72
|
"@utils/eslint-config": "1.0.4",
|
|
73
73
|
"@utils/ts-config-types": "1.0.4",
|
|
74
|
-
"@utils/ts-config": "1.0.4",
|
|
75
74
|
"@utils/tsup-config": "1.0.4"
|
|
76
75
|
},
|
|
77
76
|
"peerDependencies": {
|
|
78
|
-
"@intlayer/api": "4.0.
|
|
79
|
-
"@intlayer/
|
|
80
|
-
"@intlayer/config": "4.0.
|
|
81
|
-
"@intlayer/
|
|
77
|
+
"@intlayer/api": "4.0.5",
|
|
78
|
+
"@intlayer/dictionaries-entry": "^4.0.5",
|
|
79
|
+
"@intlayer/config": "4.0.5",
|
|
80
|
+
"@intlayer/chokidar": "4.0.5",
|
|
81
|
+
"@intlayer/editor": "4.0.5"
|
|
82
82
|
},
|
|
83
83
|
"bug": {
|
|
84
84
|
"url": "https://github.com/aymericzip/intlayer/issues"
|