@intlayer/cli 8.4.4 → 8.4.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/IntlayerEventListener.cjs +186 -1
- package/dist/cjs/IntlayerEventListener.cjs.map +1 -1
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/cjs/_virtual/_utils_asset.cjs +98 -0
- package/dist/cjs/auth/login.cjs +90 -2
- package/dist/cjs/auth/login.cjs.map +1 -1
- package/dist/cjs/build.cjs +30 -1
- package/dist/cjs/build.cjs.map +1 -1
- package/dist/cjs/ci.cjs +76 -1
- package/dist/cjs/ci.cjs.map +1 -1
- package/dist/cjs/cli.cjs +485 -1
- package/dist/cjs/cli.cjs.map +1 -1
- package/dist/cjs/config.cjs +15 -1
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/editor.cjs +50 -1
- package/dist/cjs/editor.cjs.map +1 -1
- package/dist/cjs/extract.cjs +108 -1
- package/dist/cjs/extract.cjs.map +1 -1
- package/dist/cjs/fill/deepMergeContent.cjs +27 -1
- package/dist/cjs/fill/deepMergeContent.cjs.map +1 -1
- package/dist/cjs/fill/fill.cjs +84 -1
- package/dist/cjs/fill/fill.cjs.map +1 -1
- package/dist/cjs/fill/formatAutoFilledFilePath.cjs +32 -1
- package/dist/cjs/fill/formatAutoFilledFilePath.cjs.map +1 -1
- package/dist/cjs/fill/formatFillData.cjs +87 -1
- package/dist/cjs/fill/formatFillData.cjs.map +1 -1
- package/dist/cjs/fill/getAvailableLocalesInDictionary.cjs +26 -1
- package/dist/cjs/fill/getAvailableLocalesInDictionary.cjs.map +1 -1
- package/dist/cjs/fill/getFilterMissingContentPerLocale.cjs +51 -1
- package/dist/cjs/fill/getFilterMissingContentPerLocale.cjs.map +1 -1
- package/dist/cjs/fill/index.cjs +6 -1
- package/dist/cjs/fill/listTranslationsTasks.cjs +72 -1
- package/dist/cjs/fill/listTranslationsTasks.cjs.map +1 -1
- package/dist/cjs/fill/translateDictionary.cjs +240 -1
- package/dist/cjs/fill/translateDictionary.cjs.map +1 -1
- package/dist/cjs/fill/writeFill.cjs +55 -1
- package/dist/cjs/fill/writeFill.cjs.map +1 -1
- package/dist/cjs/getTargetDictionary.cjs +36 -1
- package/dist/cjs/getTargetDictionary.cjs.map +1 -1
- package/dist/cjs/index.cjs +44 -1
- package/dist/cjs/init.cjs +22 -1
- package/dist/cjs/init.cjs.map +1 -1
- package/dist/cjs/initMCP.cjs +69 -1
- package/dist/cjs/initMCP.cjs.map +1 -1
- package/dist/cjs/initSkills.cjs +93 -1
- package/dist/cjs/initSkills.cjs.map +1 -1
- package/dist/cjs/listContentDeclaration.cjs +42 -1
- package/dist/cjs/listContentDeclaration.cjs.map +1 -1
- package/dist/cjs/listProjects.cjs +28 -1
- package/dist/cjs/listProjects.cjs.map +1 -1
- package/dist/cjs/liveSync.cjs +153 -8
- package/dist/cjs/liveSync.cjs.map +1 -1
- package/dist/cjs/pull.cjs +153 -1
- package/dist/cjs/pull.cjs.map +1 -1
- package/dist/cjs/push/pullLog.cjs +105 -3
- package/dist/cjs/push/pullLog.cjs.map +1 -1
- package/dist/cjs/push/push.cjs +212 -1
- package/dist/cjs/push/push.cjs.map +1 -1
- package/dist/cjs/pushConfig.cjs +22 -1
- package/dist/cjs/pushConfig.cjs.map +1 -1
- package/dist/cjs/pushLog.cjs +86 -3
- package/dist/cjs/pushLog.cjs.map +1 -1
- package/dist/cjs/reviewDoc/reviewDoc.cjs +73 -1
- package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -1
- package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +98 -1
- package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
- package/dist/cjs/searchDoc.cjs +41 -1
- package/dist/cjs/searchDoc.cjs.map +1 -1
- package/dist/cjs/test/index.cjs +7 -1
- package/dist/cjs/test/listMissingTranslations.cjs +52 -1
- package/dist/cjs/test/listMissingTranslations.cjs.map +1 -1
- package/dist/cjs/test/test.cjs +56 -1
- package/dist/cjs/test/test.cjs.map +1 -1
- package/dist/cjs/translateDoc/index.cjs +9 -1
- package/dist/cjs/translateDoc/translateDoc.cjs +79 -1
- package/dist/cjs/translateDoc/translateDoc.cjs.map +1 -1
- package/dist/cjs/translateDoc/translateFile.cjs +106 -2
- package/dist/cjs/translateDoc/translateFile.cjs.map +1 -1
- package/dist/cjs/translateDoc/validation.cjs +49 -5
- package/dist/cjs/translateDoc/validation.cjs.map +1 -1
- package/dist/cjs/translation-alignment/alignBlocks.cjs +67 -1
- package/dist/cjs/translation-alignment/alignBlocks.cjs.map +1 -1
- package/dist/cjs/translation-alignment/computeSimilarity.cjs +25 -1
- package/dist/cjs/translation-alignment/computeSimilarity.cjs.map +1 -1
- package/dist/cjs/translation-alignment/fingerprintBlock.cjs +23 -1
- package/dist/cjs/translation-alignment/fingerprintBlock.cjs.map +1 -1
- package/dist/cjs/translation-alignment/index.cjs +22 -1
- package/dist/cjs/translation-alignment/mapChangedLinesToBlocks.cjs +18 -1
- package/dist/cjs/translation-alignment/mapChangedLinesToBlocks.cjs.map +1 -1
- package/dist/cjs/translation-alignment/normalizeBlock.cjs +22 -1
- package/dist/cjs/translation-alignment/normalizeBlock.cjs.map +1 -1
- package/dist/cjs/translation-alignment/pipeline.cjs +37 -1
- package/dist/cjs/translation-alignment/pipeline.cjs.map +1 -1
- package/dist/cjs/translation-alignment/planActions.cjs +46 -1
- package/dist/cjs/translation-alignment/planActions.cjs.map +1 -1
- package/dist/cjs/translation-alignment/rebuildDocument.cjs +49 -2
- package/dist/cjs/translation-alignment/rebuildDocument.cjs.map +1 -1
- package/dist/cjs/translation-alignment/segmentDocument.cjs +66 -5
- package/dist/cjs/translation-alignment/segmentDocument.cjs.map +1 -1
- package/dist/cjs/utils/calculateChunks.cjs +89 -2
- package/dist/cjs/utils/calculateChunks.cjs.map +1 -1
- package/dist/cjs/utils/checkAccess.cjs +83 -1
- package/dist/cjs/utils/checkAccess.cjs.map +1 -1
- package/dist/cjs/utils/checkConfigConsistency.cjs +16 -1
- package/dist/cjs/utils/checkConfigConsistency.cjs.map +1 -1
- package/dist/cjs/utils/checkFileModifiedRange.cjs +81 -1
- package/dist/cjs/utils/checkFileModifiedRange.cjs.map +1 -1
- package/dist/cjs/utils/checkLastUpdateTime.cjs +19 -1
- package/dist/cjs/utils/checkLastUpdateTime.cjs.map +1 -1
- package/dist/cjs/utils/chunkInference.cjs +45 -1
- package/dist/cjs/utils/chunkInference.cjs.map +1 -1
- package/dist/cjs/utils/fixChunkStartEndChars.cjs +27 -3
- package/dist/cjs/utils/fixChunkStartEndChars.cjs.map +1 -1
- package/dist/cjs/utils/formatTimeDiff.cjs +20 -1
- package/dist/cjs/utils/formatTimeDiff.cjs.map +1 -1
- package/dist/cjs/utils/getIsFileUpdatedRecently.cjs +16 -1
- package/dist/cjs/utils/getIsFileUpdatedRecently.cjs.map +1 -1
- package/dist/cjs/utils/getOutputFilePath.cjs +74 -1
- package/dist/cjs/utils/getOutputFilePath.cjs.map +1 -1
- package/dist/cjs/utils/getParentPackageJSON.cjs +20 -1
- package/dist/cjs/utils/getParentPackageJSON.cjs.map +1 -1
- package/dist/cjs/utils/listSpecialChars.cjs +54 -2
- package/dist/cjs/utils/listSpecialChars.cjs.map +1 -1
- package/dist/cjs/utils/mapChunksBetweenFiles.cjs +102 -1
- package/dist/cjs/utils/mapChunksBetweenFiles.cjs.map +1 -1
- package/dist/cjs/utils/openBrowser.cjs +19 -1
- package/dist/cjs/utils/openBrowser.cjs.map +1 -1
- package/dist/cjs/utils/reorderParagraphs.cjs +91 -3
- package/dist/cjs/utils/reorderParagraphs.cjs.map +1 -1
- package/dist/cjs/utils/setupAI.cjs +66 -1
- package/dist/cjs/utils/setupAI.cjs.map +1 -1
- package/dist/cjs/watch.cjs +47 -1
- package/dist/cjs/watch.cjs.map +1 -1
- package/dist/esm/IntlayerEventListener.mjs +183 -1
- package/dist/esm/IntlayerEventListener.mjs.map +1 -1
- package/dist/esm/_virtual/_rolldown/runtime.mjs +8 -0
- package/dist/esm/_virtual/_utils_asset.mjs +97 -0
- package/dist/esm/auth/login.mjs +86 -2
- package/dist/esm/auth/login.mjs.map +1 -1
- package/dist/esm/build.mjs +28 -1
- package/dist/esm/build.mjs.map +1 -1
- package/dist/esm/ci.mjs +74 -1
- package/dist/esm/ci.mjs.map +1 -1
- package/dist/esm/cli.mjs +482 -1
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/config.mjs +13 -1
- package/dist/esm/config.mjs.map +1 -1
- package/dist/esm/editor.mjs +50 -1
- package/dist/esm/editor.mjs.map +1 -0
- package/dist/esm/extract.mjs +104 -1
- package/dist/esm/extract.mjs.map +1 -1
- package/dist/esm/fill/deepMergeContent.mjs +25 -1
- package/dist/esm/fill/deepMergeContent.mjs.map +1 -1
- package/dist/esm/fill/fill.mjs +81 -1
- package/dist/esm/fill/fill.mjs.map +1 -1
- package/dist/esm/fill/formatAutoFilledFilePath.mjs +30 -1
- package/dist/esm/fill/formatAutoFilledFilePath.mjs.map +1 -1
- package/dist/esm/fill/formatFillData.mjs +85 -1
- package/dist/esm/fill/formatFillData.mjs.map +1 -1
- package/dist/esm/fill/getAvailableLocalesInDictionary.mjs +24 -1
- package/dist/esm/fill/getAvailableLocalesInDictionary.mjs.map +1 -1
- package/dist/esm/fill/getFilterMissingContentPerLocale.mjs +49 -1
- package/dist/esm/fill/getFilterMissingContentPerLocale.mjs.map +1 -1
- package/dist/esm/fill/index.mjs +4 -1
- package/dist/esm/fill/listTranslationsTasks.mjs +69 -1
- package/dist/esm/fill/listTranslationsTasks.mjs.map +1 -1
- package/dist/esm/fill/translateDictionary.mjs +237 -1
- package/dist/esm/fill/translateDictionary.mjs.map +1 -1
- package/dist/esm/fill/writeFill.mjs +53 -1
- package/dist/esm/fill/writeFill.mjs.map +1 -1
- package/dist/esm/getTargetDictionary.mjs +33 -1
- package/dist/esm/getTargetDictionary.mjs.map +1 -1
- package/dist/esm/index.mjs +20 -1
- package/dist/esm/init.mjs +19 -1
- package/dist/esm/init.mjs.map +1 -1
- package/dist/esm/initMCP.mjs +65 -1
- package/dist/esm/initMCP.mjs.map +1 -1
- package/dist/esm/initSkills.mjs +87 -1
- package/dist/esm/initSkills.mjs.map +1 -1
- package/dist/esm/listContentDeclaration.mjs +39 -1
- package/dist/esm/listContentDeclaration.mjs.map +1 -1
- package/dist/esm/listProjects.mjs +26 -1
- package/dist/esm/listProjects.mjs.map +1 -1
- package/dist/esm/liveSync.mjs +150 -8
- package/dist/esm/liveSync.mjs.map +1 -1
- package/dist/esm/pull.mjs +150 -1
- package/dist/esm/pull.mjs.map +1 -1
- package/dist/esm/push/pullLog.mjs +102 -3
- package/dist/esm/push/pullLog.mjs.map +1 -1
- package/dist/esm/push/push.mjs +208 -1
- package/dist/esm/push/push.mjs.map +1 -1
- package/dist/esm/pushConfig.mjs +20 -1
- package/dist/esm/pushConfig.mjs.map +1 -1
- package/dist/esm/pushLog.mjs +83 -3
- package/dist/esm/pushLog.mjs.map +1 -1
- package/dist/esm/reviewDoc/reviewDoc.mjs +69 -1
- package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -1
- package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +95 -1
- package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
- package/dist/esm/searchDoc.mjs +39 -1
- package/dist/esm/searchDoc.mjs.map +1 -1
- package/dist/esm/test/index.mjs +4 -1
- package/dist/esm/test/listMissingTranslations.mjs +49 -1
- package/dist/esm/test/listMissingTranslations.mjs.map +1 -1
- package/dist/esm/test/test.mjs +53 -1
- package/dist/esm/test/test.mjs.map +1 -1
- package/dist/esm/translateDoc/index.mjs +5 -1
- package/dist/esm/translateDoc/translateDoc.mjs +75 -1
- package/dist/esm/translateDoc/translateDoc.mjs.map +1 -1
- package/dist/esm/translateDoc/translateFile.mjs +103 -2
- package/dist/esm/translateDoc/translateFile.mjs.map +1 -1
- package/dist/esm/translateDoc/validation.mjs +46 -5
- package/dist/esm/translateDoc/validation.mjs.map +1 -1
- package/dist/esm/translation-alignment/alignBlocks.mjs +66 -1
- package/dist/esm/translation-alignment/alignBlocks.mjs.map +1 -1
- package/dist/esm/translation-alignment/computeSimilarity.mjs +22 -1
- package/dist/esm/translation-alignment/computeSimilarity.mjs.map +1 -1
- package/dist/esm/translation-alignment/fingerprintBlock.mjs +20 -1
- package/dist/esm/translation-alignment/fingerprintBlock.mjs.map +1 -1
- package/dist/esm/translation-alignment/index.mjs +11 -1
- package/dist/esm/translation-alignment/mapChangedLinesToBlocks.mjs +16 -1
- package/dist/esm/translation-alignment/mapChangedLinesToBlocks.mjs.map +1 -1
- package/dist/esm/translation-alignment/normalizeBlock.mjs +20 -1
- package/dist/esm/translation-alignment/normalizeBlock.mjs.map +1 -1
- package/dist/esm/translation-alignment/pipeline.mjs +35 -1
- package/dist/esm/translation-alignment/pipeline.mjs.map +1 -1
- package/dist/esm/translation-alignment/planActions.mjs +44 -1
- package/dist/esm/translation-alignment/planActions.mjs.map +1 -1
- package/dist/esm/translation-alignment/rebuildDocument.mjs +46 -2
- package/dist/esm/translation-alignment/rebuildDocument.mjs.map +1 -1
- package/dist/esm/translation-alignment/segmentDocument.mjs +64 -5
- package/dist/esm/translation-alignment/segmentDocument.mjs.map +1 -1
- package/dist/esm/utils/calculateChunks.mjs +87 -2
- package/dist/esm/utils/calculateChunks.mjs.map +1 -1
- package/dist/esm/utils/checkAccess.mjs +79 -1
- package/dist/esm/utils/checkAccess.mjs.map +1 -1
- package/dist/esm/utils/checkConfigConsistency.mjs +14 -1
- package/dist/esm/utils/checkConfigConsistency.mjs.map +1 -1
- package/dist/esm/utils/checkFileModifiedRange.mjs +80 -1
- package/dist/esm/utils/checkFileModifiedRange.mjs.map +1 -1
- package/dist/esm/utils/checkLastUpdateTime.mjs +17 -1
- package/dist/esm/utils/checkLastUpdateTime.mjs.map +1 -1
- package/dist/esm/utils/chunkInference.mjs +43 -1
- package/dist/esm/utils/chunkInference.mjs.map +1 -1
- package/dist/esm/utils/fixChunkStartEndChars.mjs +25 -3
- package/dist/esm/utils/fixChunkStartEndChars.mjs.map +1 -1
- package/dist/esm/utils/formatTimeDiff.mjs +18 -1
- package/dist/esm/utils/formatTimeDiff.mjs.map +1 -1
- package/dist/esm/utils/getIsFileUpdatedRecently.mjs +14 -1
- package/dist/esm/utils/getIsFileUpdatedRecently.mjs.map +1 -1
- package/dist/esm/utils/getOutputFilePath.mjs +72 -1
- package/dist/esm/utils/getOutputFilePath.mjs.map +1 -1
- package/dist/esm/utils/getParentPackageJSON.mjs +18 -1
- package/dist/esm/utils/getParentPackageJSON.mjs.map +1 -1
- package/dist/esm/utils/listSpecialChars.mjs +52 -2
- package/dist/esm/utils/listSpecialChars.mjs.map +1 -1
- package/dist/esm/utils/mapChunksBetweenFiles.mjs +100 -1
- package/dist/esm/utils/mapChunksBetweenFiles.mjs.map +1 -1
- package/dist/esm/utils/openBrowser.mjs +17 -1
- package/dist/esm/utils/openBrowser.mjs.map +1 -1
- package/dist/esm/utils/reorderParagraphs.mjs +90 -3
- package/dist/esm/utils/reorderParagraphs.mjs.map +1 -1
- package/dist/esm/utils/setupAI.mjs +63 -1
- package/dist/esm/utils/setupAI.mjs.map +1 -1
- package/dist/esm/watch.mjs +45 -1
- package/dist/esm/watch.mjs.map +1 -1
- package/dist/types/fill/fill.d.ts +1 -1
- package/dist/types/fill/translateDictionary.d.ts +1 -1
- package/dist/types/getTargetDictionary.d.ts +19 -2
- package/dist/types/getTargetDictionary.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/reviewDoc/reviewDocBlockAware.d.ts +1 -1
- package/dist/types/test/index.d.ts +2 -2
- package/dist/types/test/listMissingTranslations.d.ts +28 -2
- package/dist/types/test/listMissingTranslations.d.ts.map +1 -0
- package/dist/types/test/test.d.ts +11 -2
- package/dist/types/test/test.d.ts.map +1 -0
- package/dist/types/translateDoc/index.d.ts +1 -1
- package/dist/types/translateDoc/translateDoc.d.ts +1 -1
- package/dist/types/translateDoc/translateFile.d.ts +1 -1
- package/dist/types/translateDoc/types.d.ts +48 -2
- package/dist/types/translateDoc/types.d.ts.map +1 -0
- package/dist/types/utils/chunkInference.d.ts +1 -1
- package/dist/types/utils/setupAI.d.ts +21 -2
- package/dist/types/utils/setupAI.d.ts.map +1 -0
- package/package.json +12 -12
- package/dist/cjs/_utils_asset-ghp_Cjwk.cjs +0 -2
- package/dist/cjs/chunk-Bmb41Sf3.cjs +0 -1
- package/dist/esm/_utils_asset-B187VPMw.mjs +0 -2
- package/dist/esm/editor-D8BGlLzF.mjs +0 -2
- package/dist/esm/editor-D8BGlLzF.mjs.map +0 -1
- package/dist/types/getTargetDictionary-RBSRtaQj.d.ts +0 -19
- package/dist/types/getTargetDictionary-RBSRtaQj.d.ts.map +0 -1
- package/dist/types/listMissingTranslations-DxKw7nqI.d.ts +0 -28
- package/dist/types/listMissingTranslations-DxKw7nqI.d.ts.map +0 -1
- package/dist/types/setupAI-Bosjx7ah.d.ts +0 -21
- package/dist/types/setupAI-Bosjx7ah.d.ts.map +0 -1
- package/dist/types/test-DUTiJR5_.d.ts +0 -11
- package/dist/types/test-DUTiJR5_.d.ts.map +0 -1
- package/dist/types/types-BKvc3FmV.d.ts +0 -48
- package/dist/types/types-BKvc3FmV.d.ts.map +0 -1
package/dist/esm/pull.mjs
CHANGED
|
@@ -1,2 +1,151 @@
|
|
|
1
|
-
import{checkCMSAuth
|
|
1
|
+
import { checkCMSAuth } from "./utils/checkAccess.mjs";
|
|
2
|
+
import { PullLogger } from "./push/pullLog.mjs";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { writeContentDeclaration } from "@intlayer/chokidar/build";
|
|
6
|
+
import { logConfigDetails } from "@intlayer/chokidar/cli";
|
|
7
|
+
import { parallelize } from "@intlayer/chokidar/utils";
|
|
8
|
+
import * as ANSIColors from "@intlayer/config/colors";
|
|
9
|
+
import { getAppLogger } from "@intlayer/config/logger";
|
|
10
|
+
import { getConfiguration } from "@intlayer/config/node";
|
|
11
|
+
import { getUnmergedDictionaries } from "@intlayer/unmerged-dictionaries-entry";
|
|
12
|
+
import { getIntlayerAPIProxy } from "@intlayer/api";
|
|
13
|
+
import { getProjectRequire } from "@intlayer/config/utils";
|
|
14
|
+
|
|
15
|
+
//#region src/pull.ts
|
|
16
|
+
/**
|
|
17
|
+
* Fetch distant dictionaries and write them locally,
|
|
18
|
+
* with progress indicators and concurrency control.
|
|
19
|
+
*/
|
|
20
|
+
const pull = async (options) => {
|
|
21
|
+
const appLogger = getAppLogger(options?.configOptions?.override);
|
|
22
|
+
try {
|
|
23
|
+
const config = getConfiguration(options?.configOptions);
|
|
24
|
+
logConfigDetails(options?.configOptions);
|
|
25
|
+
if (!await checkCMSAuth(config)) return;
|
|
26
|
+
const intlayerAPI = getIntlayerAPIProxy(void 0, config);
|
|
27
|
+
const unmergedDictionariesRecord = getUnmergedDictionaries(config);
|
|
28
|
+
const getDictionariesUpdateTimestampResult = await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();
|
|
29
|
+
if (!getDictionariesUpdateTimestampResult.data) throw new Error("No distant dictionaries found");
|
|
30
|
+
let distantDictionariesUpdateTimeStamp = getDictionariesUpdateTimestampResult.data;
|
|
31
|
+
if (options?.dictionaries) distantDictionariesUpdateTimeStamp = Object.fromEntries(Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => options.dictionaries?.includes(key)));
|
|
32
|
+
distantDictionariesUpdateTimeStamp = Object.fromEntries(Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {
|
|
33
|
+
const location = unmergedDictionariesRecord[key]?.[0]?.location ?? config.dictionary?.location ?? "remote";
|
|
34
|
+
return location === "remote" || location === "hybrid";
|
|
35
|
+
}));
|
|
36
|
+
const remoteDictionariesPath = join(config.system.mainDir, "remote_dictionaries.cjs");
|
|
37
|
+
const requireFunction = config.build?.require ?? getProjectRequire();
|
|
38
|
+
const remoteDictionariesRecord = existsSync(remoteDictionariesPath) ? requireFunction(remoteDictionariesPath) : {};
|
|
39
|
+
const entries = Object.entries(distantDictionariesUpdateTimeStamp);
|
|
40
|
+
const keysToFetch = entries.filter(([key, remoteUpdatedAtValue]) => {
|
|
41
|
+
if (!remoteUpdatedAtValue) return true;
|
|
42
|
+
const remoteUpdatedAt = typeof remoteUpdatedAtValue === "object" ? remoteUpdatedAtValue.updatedAt : remoteUpdatedAtValue;
|
|
43
|
+
const local = remoteDictionariesRecord[key];
|
|
44
|
+
if (!local) return true;
|
|
45
|
+
const localUpdatedAtRaw = local?.updatedAt;
|
|
46
|
+
const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
|
|
47
|
+
if (typeof localUpdatedAt !== "number") return true;
|
|
48
|
+
return remoteUpdatedAt > localUpdatedAt;
|
|
49
|
+
}).map(([key]) => key);
|
|
50
|
+
const cachedKeys = entries.filter(([key, remoteUpdatedAtValue]) => {
|
|
51
|
+
const remoteUpdatedAt = typeof remoteUpdatedAtValue === "object" ? remoteUpdatedAtValue.updatedAt : remoteUpdatedAtValue;
|
|
52
|
+
const localUpdatedAtRaw = remoteDictionariesRecord[key]?.updatedAt;
|
|
53
|
+
const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
|
|
54
|
+
return typeof localUpdatedAt === "number" && typeof remoteUpdatedAt === "number" && localUpdatedAt >= remoteUpdatedAt;
|
|
55
|
+
}).map(([key]) => key);
|
|
56
|
+
if (entries.length === 0) {
|
|
57
|
+
appLogger("No dictionaries to fetch", { level: "error" });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
appLogger("Fetching dictionaries:");
|
|
61
|
+
const dictionariesStatuses = [...cachedKeys.map((dictionaryKey) => ({
|
|
62
|
+
dictionaryKey,
|
|
63
|
+
status: "imported"
|
|
64
|
+
})), ...keysToFetch.map((dictionaryKey) => ({
|
|
65
|
+
dictionaryKey,
|
|
66
|
+
status: "pending"
|
|
67
|
+
}))];
|
|
68
|
+
const logger = new PullLogger();
|
|
69
|
+
logger.update(dictionariesStatuses.map((s) => ({
|
|
70
|
+
dictionaryKey: s.dictionaryKey,
|
|
71
|
+
status: s.status
|
|
72
|
+
})));
|
|
73
|
+
const successfullyFetchedDictionaries = [];
|
|
74
|
+
const processDictionary = async (statusObj) => {
|
|
75
|
+
const isCached = statusObj.status === "imported" || statusObj.status === "up-to-date";
|
|
76
|
+
if (!isCached) {
|
|
77
|
+
statusObj.status = "fetching";
|
|
78
|
+
logger.update([{
|
|
79
|
+
dictionaryKey: statusObj.dictionaryKey,
|
|
80
|
+
status: "fetching"
|
|
81
|
+
}]);
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
let sourceDictionary;
|
|
85
|
+
if (isCached) sourceDictionary = remoteDictionariesRecord[statusObj.dictionaryKey];
|
|
86
|
+
if (!sourceDictionary) sourceDictionary = (await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey)).data;
|
|
87
|
+
if (!sourceDictionary) throw new Error(`Dictionary ${statusObj.dictionaryKey} not found on remote`);
|
|
88
|
+
const localAndRemoteDictionary = unmergedDictionariesRecord[statusObj.dictionaryKey]?.find((d) => d.location === "hybrid");
|
|
89
|
+
if (localAndRemoteDictionary) sourceDictionary = {
|
|
90
|
+
...sourceDictionary,
|
|
91
|
+
location: "hybrid",
|
|
92
|
+
filePath: localAndRemoteDictionary.filePath,
|
|
93
|
+
localId: localAndRemoteDictionary.localId
|
|
94
|
+
};
|
|
95
|
+
const { status } = await writeContentDeclaration(sourceDictionary, config, options);
|
|
96
|
+
statusObj.status = status;
|
|
97
|
+
logger.update([{
|
|
98
|
+
dictionaryKey: statusObj.dictionaryKey,
|
|
99
|
+
status
|
|
100
|
+
}]);
|
|
101
|
+
successfullyFetchedDictionaries.push(sourceDictionary);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
statusObj.status = "error";
|
|
104
|
+
statusObj.error = error;
|
|
105
|
+
statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;
|
|
106
|
+
logger.update([{
|
|
107
|
+
dictionaryKey: statusObj.dictionaryKey,
|
|
108
|
+
status: "error"
|
|
109
|
+
}]);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
await parallelize(dictionariesStatuses, processDictionary, 5);
|
|
113
|
+
logger.finish();
|
|
114
|
+
const iconFor = (status) => {
|
|
115
|
+
switch (status) {
|
|
116
|
+
case "fetched":
|
|
117
|
+
case "imported":
|
|
118
|
+
case "updated":
|
|
119
|
+
case "up-to-date":
|
|
120
|
+
case "reimported in JSON":
|
|
121
|
+
case "new content file": return "✔";
|
|
122
|
+
case "error": return "✖";
|
|
123
|
+
default: return "⏲";
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const colorFor = (status) => {
|
|
127
|
+
switch (status) {
|
|
128
|
+
case "fetched":
|
|
129
|
+
case "imported":
|
|
130
|
+
case "updated":
|
|
131
|
+
case "up-to-date": return ANSIColors.GREEN;
|
|
132
|
+
case "reimported in JSON":
|
|
133
|
+
case "new content file": return ANSIColors.YELLOW;
|
|
134
|
+
case "error": return ANSIColors.RED;
|
|
135
|
+
default: return ANSIColors.BLUE;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
for (const s of dictionariesStatuses) {
|
|
139
|
+
const icon = iconFor(s.status);
|
|
140
|
+
const color = colorFor(s.status);
|
|
141
|
+
appLogger(` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`);
|
|
142
|
+
}
|
|
143
|
+
for (const statusObj of dictionariesStatuses) if (statusObj.errorMessage) appLogger(statusObj.errorMessage, { level: "error" });
|
|
144
|
+
} catch (error) {
|
|
145
|
+
appLogger(error, { level: "error" });
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
//#endregion
|
|
150
|
+
export { pull };
|
|
2
151
|
//# sourceMappingURL=pull.mjs.map
|
package/dist/esm/pull.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.mjs","names":[],"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n type DictionaryStatus,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport { parallelize } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { PullLogger, type PullStatus } from './push/pullLog';\nimport { checkCMSAuth } from './utils/checkAccess';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, any> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries?.includes(key)\n )\n );\n }\n\n // Filter by location\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {\n const localDictionaries = unmergedDictionariesRecord[key];\n const location =\n localDictionaries?.[0]?.location ??\n config.dictionary?.location ??\n 'remote';\n\n return location === 'remote' || location === 'hybrid';\n })\n );\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.system.mainDir,\n 'remote_dictionaries.cjs'\n );\n const requireFunction = config.build?.require ?? getProjectRequire();\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (requireFunction(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n if (!remoteUpdatedAtValue) return true;\n\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Check if there is a local version of this dictionary that is hybrid\n const localDictionaries =\n unmergedDictionariesRecord[statusObj.dictionaryKey];\n const localAndRemoteDictionary = localDictionaries?.find(\n (d) => d.location === 'hybrid'\n );\n\n if (localAndRemoteDictionary) {\n // We want to preserve the local properties but use the remote content\n sourceDictionary = {\n ...sourceDictionary,\n location: 'hybrid',\n filePath: localAndRemoteDictionary.filePath,\n localId: localAndRemoteDictionary.localId,\n };\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pull.mjs","names":[],"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n type DictionaryStatus,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport { parallelize } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { PullLogger, type PullStatus } from './push/pullLog';\nimport { checkCMSAuth } from './utils/checkAccess';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, any> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries?.includes(key)\n )\n );\n }\n\n // Filter by location\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {\n const localDictionaries = unmergedDictionariesRecord[key];\n const location =\n localDictionaries?.[0]?.location ??\n config.dictionary?.location ??\n 'remote';\n\n return location === 'remote' || location === 'hybrid';\n })\n );\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.system.mainDir,\n 'remote_dictionaries.cjs'\n );\n const requireFunction = config.build?.require ?? getProjectRequire();\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (requireFunction(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n if (!remoteUpdatedAtValue) return true;\n\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Check if there is a local version of this dictionary that is hybrid\n const localDictionaries =\n unmergedDictionariesRecord[statusObj.dictionaryKey];\n const localAndRemoteDictionary = localDictionaries?.find(\n (d) => d.location === 'hybrid'\n );\n\n if (localAndRemoteDictionary) {\n // We want to preserve the local properties but use the remote content\n sourceDictionary = {\n ...sourceDictionary,\n location: 'hybrid',\n filePath: localAndRemoteDictionary.filePath,\n localId: localAndRemoteDictionary.localId,\n };\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,103 @@
|
|
|
1
|
-
import*
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as ANSIColors from "@intlayer/config/colors";
|
|
2
|
+
import { colorize, spinnerFrames } from "@intlayer/config/logger";
|
|
3
|
+
import { getConfiguration } from "@intlayer/config/node";
|
|
4
|
+
|
|
5
|
+
//#region src/push/pullLog.ts
|
|
6
|
+
var PullLogger = class {
|
|
7
|
+
statuses = [];
|
|
8
|
+
spinnerTimer = null;
|
|
9
|
+
spinnerIndex = 0;
|
|
10
|
+
renderedLines = 0;
|
|
11
|
+
spinnerFrames = spinnerFrames;
|
|
12
|
+
isFinished = false;
|
|
13
|
+
prefix;
|
|
14
|
+
lastRenderedState = "";
|
|
15
|
+
constructor() {
|
|
16
|
+
this.prefix = getConfiguration().log.prefix;
|
|
17
|
+
}
|
|
18
|
+
update(newStatuses) {
|
|
19
|
+
if (this.isFinished) return;
|
|
20
|
+
for (const status of newStatuses) {
|
|
21
|
+
const index = this.statuses.findIndex((s) => s.dictionaryKey === status.dictionaryKey);
|
|
22
|
+
if (index >= 0) this.statuses[index] = status;
|
|
23
|
+
else this.statuses.push(status);
|
|
24
|
+
}
|
|
25
|
+
this.startSpinner();
|
|
26
|
+
this.render();
|
|
27
|
+
}
|
|
28
|
+
finish() {
|
|
29
|
+
this.isFinished = true;
|
|
30
|
+
this.stopSpinner();
|
|
31
|
+
this.render();
|
|
32
|
+
}
|
|
33
|
+
startSpinner() {
|
|
34
|
+
if (this.spinnerTimer || this.isFinished) return;
|
|
35
|
+
this.spinnerTimer = setInterval(() => {
|
|
36
|
+
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
|
|
37
|
+
this.render();
|
|
38
|
+
}, 100);
|
|
39
|
+
}
|
|
40
|
+
stopSpinner() {
|
|
41
|
+
if (!this.spinnerTimer) return;
|
|
42
|
+
clearInterval(this.spinnerTimer);
|
|
43
|
+
this.spinnerTimer = null;
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
const { total, done, success, errors } = this.computeProgress();
|
|
47
|
+
const frame = this.spinnerFrames[this.spinnerIndex];
|
|
48
|
+
const lines = [];
|
|
49
|
+
const isDone = done === total;
|
|
50
|
+
const progressLabel = `dictionaries: ${done}/${total}`;
|
|
51
|
+
const details = [];
|
|
52
|
+
if (success > 0) details.push(`ok: ${success}`);
|
|
53
|
+
if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));
|
|
54
|
+
const suffix = details.length > 0 ? ` (${details.join(", ")})` : "";
|
|
55
|
+
if (isDone) lines.push(`${this.prefix} ${colorize("✔", ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`);
|
|
56
|
+
else lines.push(`${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`);
|
|
57
|
+
const currentState = lines.join("\n");
|
|
58
|
+
if (currentState === this.lastRenderedState) return;
|
|
59
|
+
this.lastRenderedState = currentState;
|
|
60
|
+
if (this.renderedLines > 0) process.stdout.write(`\x1b[${this.renderedLines}F`);
|
|
61
|
+
const totalLinesToClear = Math.max(this.renderedLines, lines.length);
|
|
62
|
+
for (let i = 0; i < totalLinesToClear; i++) {
|
|
63
|
+
process.stdout.write("\x1B[2K");
|
|
64
|
+
const line = lines[i];
|
|
65
|
+
if (line !== void 0) process.stdout.write(line);
|
|
66
|
+
process.stdout.write("\n");
|
|
67
|
+
}
|
|
68
|
+
this.renderedLines = lines.length;
|
|
69
|
+
}
|
|
70
|
+
computeProgress() {
|
|
71
|
+
const keys = new Set(this.statuses.map((s) => s.dictionaryKey));
|
|
72
|
+
const doneSet = new Set([
|
|
73
|
+
"fetched",
|
|
74
|
+
"imported",
|
|
75
|
+
"updated",
|
|
76
|
+
"up-to-date",
|
|
77
|
+
"reimported in JSON",
|
|
78
|
+
"new content file",
|
|
79
|
+
"error"
|
|
80
|
+
]);
|
|
81
|
+
const successesSet = new Set([
|
|
82
|
+
"fetched",
|
|
83
|
+
"imported",
|
|
84
|
+
"updated",
|
|
85
|
+
"up-to-date",
|
|
86
|
+
"reimported in JSON",
|
|
87
|
+
"new content file"
|
|
88
|
+
]);
|
|
89
|
+
const done = this.statuses.filter((s) => doneSet.has(s.status)).length;
|
|
90
|
+
const success = this.statuses.filter((s) => successesSet.has(s.status)).length;
|
|
91
|
+
const errors = this.statuses.filter((s) => s.status === "error").length;
|
|
92
|
+
return {
|
|
93
|
+
total: keys.size,
|
|
94
|
+
done,
|
|
95
|
+
success,
|
|
96
|
+
errors
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
export { PullLogger };
|
|
4
103
|
//# sourceMappingURL=pullLog.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pullLog.mjs","names":[],"sources":["../../../src/push/pullLog.ts"],"sourcesContent":["import type { DictionaryStatus } from '@intlayer/chokidar/build';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, spinnerFrames } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\n\nexport type PullStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching';\n errorMessage?: string;\n};\n\nexport class PullLogger {\n private statuses: PullStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n\n constructor() {\n const configuration = getConfiguration();\n this.prefix = configuration.log.prefix;\n }\n\n update(newStatuses: PullStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) => s.dictionaryKey === status.dictionaryKey\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n private render() {\n const { total, done, success, errors } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const lines: string[] = [];\n\n const isDone = done === total;\n const progressLabel = `dictionaries: ${done}/${total}`;\n const details: string[] = [];\n if (success > 0) details.push(`ok: ${success}`);\n if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));\n\n const suffix = details.length > 0 ? ` (${details.join(', ')})` : '';\n\n if (isDone) {\n lines.push(\n `${this.prefix} ${colorize('✔', ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`\n );\n }\n\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const keys = new Set(this.statuses.map((s) => s.dictionaryKey));\n\n const doneSet = new Set<DictionaryStatus | 'error'>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n 'error',\n ] as const);\n\n const successesSet = new Set<DictionaryStatus>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n ] as const);\n\n const done = this.statuses.filter((s) =>\n doneSet.has(s.status as any)\n ).length;\n const success = this.statuses.filter((s) =>\n successesSet.has(s.status as any)\n ).length;\n const errors = this.statuses.filter((s) => s.status === 'error').length;\n\n return {\n total: keys.size,\n done,\n success,\n errors,\n } as const;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"pullLog.mjs","names":[],"sources":["../../../src/push/pullLog.ts"],"sourcesContent":["import type { DictionaryStatus } from '@intlayer/chokidar/build';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, spinnerFrames } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\n\nexport type PullStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching';\n errorMessage?: string;\n};\n\nexport class PullLogger {\n private statuses: PullStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n\n constructor() {\n const configuration = getConfiguration();\n this.prefix = configuration.log.prefix;\n }\n\n update(newStatuses: PullStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) => s.dictionaryKey === status.dictionaryKey\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n private render() {\n const { total, done, success, errors } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const lines: string[] = [];\n\n const isDone = done === total;\n const progressLabel = `dictionaries: ${done}/${total}`;\n const details: string[] = [];\n if (success > 0) details.push(`ok: ${success}`);\n if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));\n\n const suffix = details.length > 0 ? ` (${details.join(', ')})` : '';\n\n if (isDone) {\n lines.push(\n `${this.prefix} ${colorize('✔', ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`\n );\n }\n\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const keys = new Set(this.statuses.map((s) => s.dictionaryKey));\n\n const doneSet = new Set<DictionaryStatus | 'error'>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n 'error',\n ] as const);\n\n const successesSet = new Set<DictionaryStatus>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n ] as const);\n\n const done = this.statuses.filter((s) =>\n doneSet.has(s.status as any)\n ).length;\n const success = this.statuses.filter((s) =>\n successesSet.has(s.status as any)\n ).length;\n const errors = this.statuses.filter((s) => s.status === 'error').length;\n\n return {\n total: keys.size,\n done,\n success,\n errors,\n } as const;\n }\n}\n"],"mappings":"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"}
|
package/dist/esm/push/push.mjs
CHANGED
|
@@ -1,2 +1,209 @@
|
|
|
1
|
-
import{checkCMSAuth
|
|
1
|
+
import { checkCMSAuth } from "../utils/checkAccess.mjs";
|
|
2
|
+
import { PushLogger } from "../pushLog.mjs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { prepareIntlayer, writeContentDeclaration } from "@intlayer/chokidar/build";
|
|
5
|
+
import { listGitFiles, logConfigDetails } from "@intlayer/chokidar/cli";
|
|
6
|
+
import { formatPath, parallelize } from "@intlayer/chokidar/utils";
|
|
7
|
+
import * as ANSIColors from "@intlayer/config/colors";
|
|
8
|
+
import { colorize, colorizeKey, getAppLogger } from "@intlayer/config/logger";
|
|
9
|
+
import { getConfiguration } from "@intlayer/config/node";
|
|
10
|
+
import { getUnmergedDictionaries } from "@intlayer/unmerged-dictionaries-entry";
|
|
11
|
+
import { getIntlayerAPIProxy } from "@intlayer/api";
|
|
12
|
+
import * as fsPromises from "node:fs/promises";
|
|
13
|
+
|
|
14
|
+
//#region src/push/push.ts
|
|
15
|
+
const statusIconsAndColors = {
|
|
16
|
+
pushed: {
|
|
17
|
+
icon: "✔",
|
|
18
|
+
color: ANSIColors.GREEN
|
|
19
|
+
},
|
|
20
|
+
modified: {
|
|
21
|
+
icon: "✔",
|
|
22
|
+
color: ANSIColors.GREEN
|
|
23
|
+
},
|
|
24
|
+
error: {
|
|
25
|
+
icon: "✖",
|
|
26
|
+
color: ANSIColors.RED
|
|
27
|
+
},
|
|
28
|
+
default: {
|
|
29
|
+
icon: "⏲",
|
|
30
|
+
color: ANSIColors.BLUE
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const getIconAndColor = (status) => {
|
|
34
|
+
return statusIconsAndColors[status] ?? statusIconsAndColors.default;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Get all local dictionaries and push them simultaneously.
|
|
38
|
+
*/
|
|
39
|
+
const push = async (options) => {
|
|
40
|
+
const config = getConfiguration(options?.configOptions);
|
|
41
|
+
logConfigDetails(options?.configOptions);
|
|
42
|
+
const appLogger = getAppLogger(config);
|
|
43
|
+
if (options?.build === true) await prepareIntlayer(config, { forceRun: true });
|
|
44
|
+
else if (typeof options?.build === "undefined") await prepareIntlayer(config);
|
|
45
|
+
try {
|
|
46
|
+
if (!await checkCMSAuth(config)) return;
|
|
47
|
+
const intlayerAPI = getIntlayerAPIProxy(void 0, config);
|
|
48
|
+
const unmergedDictionariesRecord = getUnmergedDictionaries(config);
|
|
49
|
+
const allDictionaries = Object.values(unmergedDictionariesRecord).flat();
|
|
50
|
+
const customLocations = Array.from(new Set(allDictionaries.map((dictionary) => dictionary.location).filter((location) => location && ![
|
|
51
|
+
"remote",
|
|
52
|
+
"local",
|
|
53
|
+
"hybrid"
|
|
54
|
+
].includes(location))));
|
|
55
|
+
let selectedCustomLocations = [];
|
|
56
|
+
if (customLocations.length > 0) {
|
|
57
|
+
const { multiselect, confirm, isCancel } = await import("@clack/prompts");
|
|
58
|
+
if (customLocations.length === 1) {
|
|
59
|
+
const shouldPush = await confirm({
|
|
60
|
+
message: `Do you want to push dictionaries with custom location ${colorize(customLocations[0], ANSIColors.BLUE, ANSIColors.RESET)}?`,
|
|
61
|
+
initialValue: false
|
|
62
|
+
});
|
|
63
|
+
if (isCancel(shouldPush)) return;
|
|
64
|
+
if (shouldPush) selectedCustomLocations = [customLocations[0]];
|
|
65
|
+
} else {
|
|
66
|
+
const selected = await multiselect({
|
|
67
|
+
message: "Select custom locations to push:",
|
|
68
|
+
options: customLocations.map((location) => ({
|
|
69
|
+
value: location,
|
|
70
|
+
label: location
|
|
71
|
+
})),
|
|
72
|
+
required: false
|
|
73
|
+
});
|
|
74
|
+
if (isCancel(selected)) return;
|
|
75
|
+
selectedCustomLocations = selected;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
let dictionaries = allDictionaries.filter((dictionary) => {
|
|
79
|
+
const location = dictionary.location ?? config.dictionary?.location ?? "local";
|
|
80
|
+
return location === "remote" || location === "hybrid" || selectedCustomLocations.includes(location);
|
|
81
|
+
});
|
|
82
|
+
if (dictionaries.length === 0) {
|
|
83
|
+
appLogger(`No dictionaries found to push. Only dictionaries with location ${colorize("remote", ANSIColors.BLUE, ANSIColors.RESET)}, ${colorize("hybrid", ANSIColors.BLUE, ANSIColors.RESET)} or selected custom locations are pushed.`, { level: "warn" });
|
|
84
|
+
appLogger(`You can set the location in your dictionary file (e.g. ${colorize("{ key: 'my-key', location: 'hybrid', ... }", ANSIColors.BLUE, ANSIColors.RESET)} or globally in your intlayer.config.ts file (e.g. ${colorize("{ dictionary: { location: 'hybrid' } }", ANSIColors.BLUE, ANSIColors.RESET)}).`, { level: "info" });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const existingDictionariesKeys = Object.keys(unmergedDictionariesRecord);
|
|
88
|
+
if (options?.dictionaries) {
|
|
89
|
+
const noneExistingDictionariesOption = options.dictionaries.filter((dictionaryId) => !existingDictionariesKeys.includes(dictionaryId));
|
|
90
|
+
if (noneExistingDictionariesOption.length > 0) appLogger(`The following dictionaries do not exist: ${noneExistingDictionariesOption.join(", ")} and have been ignored.`, { level: "error" });
|
|
91
|
+
dictionaries = dictionaries.filter((dictionary) => options.dictionaries?.includes(dictionary.key));
|
|
92
|
+
}
|
|
93
|
+
if (options?.gitOptions) {
|
|
94
|
+
const gitFiles = await listGitFiles(options.gitOptions);
|
|
95
|
+
dictionaries = dictionaries.filter((dictionary) => gitFiles.includes(join(config.system.baseDir, dictionary.filePath ?? "")));
|
|
96
|
+
}
|
|
97
|
+
if (dictionaries.length === 0) {
|
|
98
|
+
appLogger("No local dictionaries found", { level: "error" });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
appLogger("Pushing dictionaries:");
|
|
102
|
+
const dictionariesStatuses = dictionaries.map((dictionary) => ({
|
|
103
|
+
dictionary,
|
|
104
|
+
status: "pending"
|
|
105
|
+
}));
|
|
106
|
+
const logger = new PushLogger();
|
|
107
|
+
logger.update(dictionariesStatuses.map((s) => ({
|
|
108
|
+
dictionaryKey: s.dictionary.key,
|
|
109
|
+
status: "pending"
|
|
110
|
+
})));
|
|
111
|
+
const successfullyPushedDictionaries = [];
|
|
112
|
+
const processDictionary = async (statusObj) => {
|
|
113
|
+
statusObj.status = "pushing";
|
|
114
|
+
logger.update([{
|
|
115
|
+
dictionaryKey: statusObj.dictionary.key,
|
|
116
|
+
status: "pushing"
|
|
117
|
+
}]);
|
|
118
|
+
try {
|
|
119
|
+
const pushResult = await intlayerAPI.dictionary.pushDictionaries([statusObj.dictionary]);
|
|
120
|
+
const updatedDictionaries = pushResult.data?.updatedDictionaries ?? [];
|
|
121
|
+
const newDictionaries = pushResult.data?.newDictionaries ?? [];
|
|
122
|
+
const allDictionaries = [...updatedDictionaries, ...newDictionaries];
|
|
123
|
+
for (const remoteDictionaryData of allDictionaries) {
|
|
124
|
+
const localDictionary = unmergedDictionariesRecord[remoteDictionaryData.key]?.find((dictionary) => dictionary.localId === remoteDictionaryData.localId);
|
|
125
|
+
if (!localDictionary) continue;
|
|
126
|
+
await writeContentDeclaration({
|
|
127
|
+
...localDictionary,
|
|
128
|
+
id: remoteDictionaryData.id
|
|
129
|
+
}, config);
|
|
130
|
+
}
|
|
131
|
+
if (updatedDictionaries.some((dictionary) => dictionary.key === statusObj.dictionary.key)) {
|
|
132
|
+
statusObj.status = "modified";
|
|
133
|
+
successfullyPushedDictionaries.push(statusObj.dictionary);
|
|
134
|
+
logger.update([{
|
|
135
|
+
dictionaryKey: statusObj.dictionary.key,
|
|
136
|
+
status: "modified"
|
|
137
|
+
}]);
|
|
138
|
+
} else if (newDictionaries.some((dictionary) => dictionary.key === statusObj.dictionary.key)) {
|
|
139
|
+
statusObj.status = "pushed";
|
|
140
|
+
successfullyPushedDictionaries.push(statusObj.dictionary);
|
|
141
|
+
logger.update([{
|
|
142
|
+
dictionaryKey: statusObj.dictionary.key,
|
|
143
|
+
status: "pushed"
|
|
144
|
+
}]);
|
|
145
|
+
} else statusObj.status = "unknown";
|
|
146
|
+
} catch (error) {
|
|
147
|
+
statusObj.status = "error";
|
|
148
|
+
statusObj.error = error;
|
|
149
|
+
statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;
|
|
150
|
+
logger.update([{
|
|
151
|
+
dictionaryKey: statusObj.dictionary.key,
|
|
152
|
+
status: "error"
|
|
153
|
+
}]);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
await parallelize(dictionariesStatuses, processDictionary, 5);
|
|
157
|
+
logger.finish();
|
|
158
|
+
for (const dictionaryStatus of dictionariesStatuses) {
|
|
159
|
+
const { icon, color } = getIconAndColor(dictionaryStatus.status);
|
|
160
|
+
appLogger(` - ${colorizeKey(dictionaryStatus.dictionary.key)} ${ANSIColors.GREY}[${color}${icon} ${dictionaryStatus.status}${ANSIColors.GREY}]${ANSIColors.RESET}`);
|
|
161
|
+
}
|
|
162
|
+
for (const statusObj of dictionariesStatuses) if (statusObj.errorMessage) appLogger(statusObj.errorMessage, { level: "error" });
|
|
163
|
+
const deleteOption = options?.deleteLocaleDictionary;
|
|
164
|
+
const keepOption = options?.keepLocaleDictionary;
|
|
165
|
+
if (deleteOption && keepOption) throw new Error("Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.");
|
|
166
|
+
if (deleteOption) await deleteLocalDictionaries(successfullyPushedDictionaries, options);
|
|
167
|
+
else if (keepOption) {} else {
|
|
168
|
+
const remoteDictionaries = successfullyPushedDictionaries.filter((dictionary) => dictionary.location === "remote");
|
|
169
|
+
const remoteDictionariesKeys = remoteDictionaries.map((dictionary) => dictionary.key);
|
|
170
|
+
if (remoteDictionaries.length > 0) {
|
|
171
|
+
const { confirm, isCancel } = await import("@clack/prompts");
|
|
172
|
+
const shouldDelete = await confirm({
|
|
173
|
+
message: `Do you want to delete the local dictionaries that were successfully pushed? ${colorize("(Dictionaries:", ANSIColors.GREY, ANSIColors.RESET)} ${colorizeKey(remoteDictionariesKeys)}${colorize(")", ANSIColors.GREY, ANSIColors.RESET)}`,
|
|
174
|
+
initialValue: false
|
|
175
|
+
});
|
|
176
|
+
if (isCancel(shouldDelete)) return;
|
|
177
|
+
if (shouldDelete) await deleteLocalDictionaries(remoteDictionaries, options);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
appLogger(error, { level: "error" });
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const deleteLocalDictionaries = async (dictionariesToDelete, options) => {
|
|
185
|
+
const appLogger = getAppLogger(getConfiguration(options?.configOptions));
|
|
186
|
+
const filePathsSet = /* @__PURE__ */ new Set();
|
|
187
|
+
for (const dictionary of dictionariesToDelete) {
|
|
188
|
+
const { filePath } = dictionary;
|
|
189
|
+
if (!filePath) {
|
|
190
|
+
appLogger(`Dictionary ${colorizeKey(dictionary.key)} does not have a file path`, { level: "error" });
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
filePathsSet.add(filePath);
|
|
194
|
+
}
|
|
195
|
+
for (const filePath of filePathsSet) try {
|
|
196
|
+
const stats = await fsPromises.lstat(filePath);
|
|
197
|
+
if (stats.isFile()) {
|
|
198
|
+
await fsPromises.unlink(filePath);
|
|
199
|
+
appLogger(`Deleted file ${formatPath(filePath)}`, {});
|
|
200
|
+
} else if (stats.isDirectory()) appLogger(`Path is a directory ${formatPath(filePath)}, skipping.`, {});
|
|
201
|
+
else appLogger(`Unknown file type for ${formatPath(filePath)}, skipping.`, {});
|
|
202
|
+
} catch (err) {
|
|
203
|
+
appLogger(`Error deleting ${formatPath(filePath)}: ${err}`, { level: "error" });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
//#endregion
|
|
208
|
+
export { push };
|
|
2
209
|
//# sourceMappingURL=push.mjs.map
|