@intlayer/engine 9.1.3 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/initConfig/templates/cjs.txt +4 -1
- package/dist/assets/initConfig/templates/json.txt +4 -1
- package/dist/assets/initConfig/templates/mjs.txt +4 -1
- package/dist/assets/initConfig/templates/ts.txt +4 -1
- package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs +14 -2
- package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +24 -4
- package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs +43 -6
- package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs +96 -0
- package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -0
- package/dist/cjs/docReview/alignBlocks.cjs +57 -8
- package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
- package/dist/cjs/docReview/rebuildDocument.cjs +37 -9
- package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
- package/dist/cjs/docReview/segmentDocument.cjs +19 -2
- package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
- package/dist/cjs/fetchDistantDictionaries.cjs +107 -13
- package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs +4 -2
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +3 -2
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/log.cjs +28 -5
- package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
- package/dist/cjs/prepareIntlayer.cjs +7 -3
- package/dist/cjs/prepareIntlayer.cjs.map +1 -1
- package/dist/cjs/utils/chunkArray.cjs +24 -0
- package/dist/cjs/utils/chunkArray.cjs.map +1 -0
- package/dist/cjs/utils/index.cjs +2 -0
- package/dist/cjs/utils/runOnce.cjs +129 -50
- package/dist/cjs/utils/runOnce.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +153 -92
- package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
- package/dist/cjs/writeFileIfChanged.cjs +14 -7
- package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs +15 -3
- package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +24 -4
- package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs +43 -6
- package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/writeNestedDictionary.mjs +92 -0
- package/dist/esm/buildIntlayerDictionary/writeNestedDictionary.mjs.map +1 -0
- package/dist/esm/docReview/alignBlocks.mjs +57 -8
- package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
- package/dist/esm/docReview/rebuildDocument.mjs +37 -9
- package/dist/esm/docReview/rebuildDocument.mjs.map +1 -1
- package/dist/esm/docReview/segmentDocument.mjs +19 -2
- package/dist/esm/docReview/segmentDocument.mjs.map +1 -1
- package/dist/esm/fetchDistantDictionaries.mjs +107 -13
- package/dist/esm/fetchDistantDictionaries.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +1 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadDictionaries.mjs +4 -2
- package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +3 -2
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/log.mjs +28 -5
- package/dist/esm/loadDictionaries/log.mjs.map +1 -1
- package/dist/esm/prepareIntlayer.mjs +7 -3
- package/dist/esm/prepareIntlayer.mjs.map +1 -1
- package/dist/esm/utils/chunkArray.mjs +22 -0
- package/dist/esm/utils/chunkArray.mjs.map +1 -0
- package/dist/esm/utils/index.mjs +2 -1
- package/dist/esm/utils/runOnce.mjs +129 -50
- package/dist/esm/utils/runOnce.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/transformJSFile.mjs +153 -92
- package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
- package/dist/esm/writeFileIfChanged.mjs +15 -8
- package/dist/esm/writeFileIfChanged.mjs.map +1 -1
- package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts +14 -2
- package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts +16 -2
- package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeNestedDictionary.d.ts +54 -0
- package/dist/types/buildIntlayerDictionary/writeNestedDictionary.d.ts.map +1 -0
- package/dist/types/docReview/alignBlocks.d.ts +4 -2
- package/dist/types/docReview/alignBlocks.d.ts.map +1 -1
- package/dist/types/docReview/rebuildDocument.d.ts.map +1 -1
- package/dist/types/docReview/segmentDocument.d.ts.map +1 -1
- package/dist/types/docReview/types.d.ts +9 -0
- package/dist/types/docReview/types.d.ts.map +1 -1
- package/dist/types/fetchDistantDictionaries.d.ts +26 -0
- package/dist/types/fetchDistantDictionaries.d.ts.map +1 -1
- package/dist/types/formatDictionary.d.ts +2 -0
- package/dist/types/formatDictionary.d.ts.map +1 -1
- package/dist/types/loadDictionaries/log.d.ts +16 -1
- package/dist/types/loadDictionaries/log.d.ts.map +1 -1
- package/dist/types/utils/chunkArray.d.ts +16 -0
- package/dist/types/utils/chunkArray.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +3 -2
- package/dist/types/utils/runOnce.d.ts +30 -6
- package/dist/types/utils/runOnce.d.ts.map +1 -1
- package/dist/types/writeContentDeclaration/transformJSFile.d.ts.map +1 -1
- package/package.json +11 -11
|
@@ -81,11 +81,13 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
81
81
|
const { plugins } = configuration;
|
|
82
82
|
const loadDictionariesStartTime = Date.now();
|
|
83
83
|
(0, _intlayer_config_logger.getAppLogger)(configuration)("Dictionaries:", { isVerbose: true });
|
|
84
|
-
const
|
|
84
|
+
const pluginsWithLoadDictionaries = (await Promise.all(plugins ?? [])).filter((plugin) => plugin.loadDictionaries);
|
|
85
|
+
logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));
|
|
86
|
+
const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(async (plugin) => {
|
|
85
87
|
try {
|
|
86
88
|
return await plugin.loadDictionaries?.({ configuration }) ?? [];
|
|
87
89
|
} catch (error) {
|
|
88
|
-
logger.setPluginError(error);
|
|
90
|
+
logger.setPluginError(error, plugin.name);
|
|
89
91
|
return [];
|
|
90
92
|
}
|
|
91
93
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations","loadRemoteDictionaries"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n dictionaryKey: string;\n type: 'local' | 'remote';\n status:\n | 'pending' // Key found but not fetched yet\n | 'fetching' // If dictionary fetch is in progress\n | 'fetched' // If dictionary fetch succeeded\n | 'error' // If dictionary fetch failed\n | 'imported' // If dictionary already fetched and still up to date\n | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n | 'building' // If dictionary is being built\n | 'built'; // If dictionary is built;\n error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n for (const incoming of statuses) {\n const index = updated.findIndex(\n (s) =>\n s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n );\n if (index >= 0) {\n updated[index] = incoming;\n } else {\n updated.push(incoming);\n }\n }\n\n loadDictionariesStatus = updated;\n logger.update(statuses);\n\n return updated;\n};\n\ntype StatusRecord = {\n local?: DictionariesStatus['status'];\n remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n if (configuration.log.mode !== 'verbose') return;\n\n const appLogger = getAppLogger(configuration);\n\n // Aggregate by dictionary key\n const byKey = new Map<string, StatusRecord>();\n for (const status of loadDictionariesStatus) {\n const rec = byKey.get(status.dictionaryKey) ?? {};\n if (status.type === 'local') rec.local = status.status;\n if (status.type === 'remote') rec.remote = status.status;\n byKey.set(status.dictionaryKey, rec);\n }\n\n const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n // Compute the max visible length of the local label to align distant labels\n let maxLocalLabelLen = 0;\n for (const key of keys) {\n const rec = byKey.get(key)!;\n if (rec.local) {\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n if (visibleLocal.length > maxLocalLabelLen) {\n maxLocalLabelLen = visibleLocal.length;\n }\n }\n }\n\n for (const key of keys) {\n const rec = byKey.get(key)!;\n const labels: string[] = [];\n\n if (rec.local) {\n const inner = colorize(\n `${iconFor(rec.local)} ${rec.local}`,\n colorFor(rec.local)\n );\n const coloredLocal =\n `${ANSIColors.GREY}[` +\n colorize('local: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n // Pad to align distant label across rows\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n labels.push(coloredLocal + ' '.repeat(pad));\n } else {\n // If no local label, insert spaces to keep distant aligned\n labels.push(' '.repeat(maxLocalLabelLen));\n }\n\n if (rec.remote) {\n const inner = colorize(\n `${iconFor(rec.remote)} ${rec.remote}`,\n colorFor(rec.remote)\n );\n labels.push(\n `${ANSIColors.GREY}[` +\n colorize('distant: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n appLogger(\n ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n );\n }\n};\n\nexport const loadDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<{\n localDictionaries: Dictionary[];\n remoteDictionaries: Dictionary[];\n pluginDictionaries: Dictionary[];\n time: {\n localDictionaries: number;\n remoteDictionaries: number;\n pluginDictionaries: number;\n };\n}> => {\n const { plugins } = configuration;\n const loadDictionariesStartTime = Date.now();\n const appLogger = getAppLogger(configuration);\n\n appLogger('Dictionaries:', { isVerbose: true });\n\n // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n const resolvedPlugins = await Promise.all(plugins ?? []);\n\n const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n (plugin) => plugin.loadDictionaries\n );\n\n const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n async (plugin) => {\n try {\n const res = await plugin.loadDictionaries?.({\n configuration,\n });\n\n return (res as Dictionary[] | undefined) ?? [];\n } catch (error) {\n logger.setPluginError(error as Error);\n\n return [];\n }\n }\n );\n\n const pluginDictionaries: Dictionary[] = await Promise.all(\n loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n )\n .then((dictionaries) => dictionaries.flat())\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n logger.setPluginTotal(pluginDictionaries.length);\n logger.setPluginDone(pluginDictionaries.length);\n\n const pluginDictionariesTime = Date.now();\n\n const files = Array.isArray(contentDeclarationsPaths)\n ? contentDeclarationsPaths\n : [contentDeclarationsPaths];\n\n const localDictionaries: Dictionary[] = await loadContentDeclarations(\n files,\n configuration,\n setLoadDictionariesStatus\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n const localDictionariesTime = Date.now();\n\n const localDictionariesStatus = localDictionaries.map(\n (dictionary) =>\n ({\n dictionaryKey: dictionary.key,\n type: 'local',\n status: 'built',\n }) as const\n );\n\n setLoadDictionariesStatus(localDictionariesStatus);\n\n const hasRemoteDictionaries = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n if (hasRemoteDictionaries) {\n // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n logger.setExpectRemote(true);\n }\n\n let remoteDictionaries: Dictionary[] = [];\n\n if (hasRemoteDictionaries) {\n remoteDictionaries = await loadRemoteDictionaries(\n configuration,\n setLoadDictionariesStatus,\n {\n onStartRemoteCheck: () => logger.startRemoteCheck(),\n onStopRemoteCheck: () => logger.stopRemoteCheck(),\n onError: (e) => logger.setRemoteError(e),\n }\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n }\n\n const remoteDictionariesTime = Date.now();\n\n // Stop spinner and show final progress line(s)\n logger.finish();\n\n printSummary(configuration);\n\n return {\n localDictionaries,\n remoteDictionaries,\n pluginDictionaries,\n time: {\n localDictionaries: localDictionariesTime - pluginDictionariesTime,\n remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations","loadRemoteDictionaries"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n dictionaryKey: string;\n type: 'local' | 'remote';\n status:\n | 'pending' // Key found but not fetched yet\n | 'fetching' // If dictionary fetch is in progress\n | 'fetched' // If dictionary fetch succeeded\n | 'error' // If dictionary fetch failed\n | 'imported' // If dictionary already fetched and still up to date\n | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n | 'building' // If dictionary is being built\n | 'built'; // If dictionary is built;\n error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n for (const incoming of statuses) {\n const index = updated.findIndex(\n (s) =>\n s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n );\n if (index >= 0) {\n updated[index] = incoming;\n } else {\n updated.push(incoming);\n }\n }\n\n loadDictionariesStatus = updated;\n logger.update(statuses);\n\n return updated;\n};\n\ntype StatusRecord = {\n local?: DictionariesStatus['status'];\n remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n if (configuration.log.mode !== 'verbose') return;\n\n const appLogger = getAppLogger(configuration);\n\n // Aggregate by dictionary key\n const byKey = new Map<string, StatusRecord>();\n for (const status of loadDictionariesStatus) {\n const rec = byKey.get(status.dictionaryKey) ?? {};\n if (status.type === 'local') rec.local = status.status;\n if (status.type === 'remote') rec.remote = status.status;\n byKey.set(status.dictionaryKey, rec);\n }\n\n const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n // Compute the max visible length of the local label to align distant labels\n let maxLocalLabelLen = 0;\n for (const key of keys) {\n const rec = byKey.get(key)!;\n if (rec.local) {\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n if (visibleLocal.length > maxLocalLabelLen) {\n maxLocalLabelLen = visibleLocal.length;\n }\n }\n }\n\n for (const key of keys) {\n const rec = byKey.get(key)!;\n const labels: string[] = [];\n\n if (rec.local) {\n const inner = colorize(\n `${iconFor(rec.local)} ${rec.local}`,\n colorFor(rec.local)\n );\n const coloredLocal =\n `${ANSIColors.GREY}[` +\n colorize('local: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n // Pad to align distant label across rows\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n labels.push(coloredLocal + ' '.repeat(pad));\n } else {\n // If no local label, insert spaces to keep distant aligned\n labels.push(' '.repeat(maxLocalLabelLen));\n }\n\n if (rec.remote) {\n const inner = colorize(\n `${iconFor(rec.remote)} ${rec.remote}`,\n colorFor(rec.remote)\n );\n labels.push(\n `${ANSIColors.GREY}[` +\n colorize('distant: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n appLogger(\n ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n );\n }\n};\n\nexport const loadDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<{\n localDictionaries: Dictionary[];\n remoteDictionaries: Dictionary[];\n pluginDictionaries: Dictionary[];\n time: {\n localDictionaries: number;\n remoteDictionaries: number;\n pluginDictionaries: number;\n };\n}> => {\n const { plugins } = configuration;\n const loadDictionariesStartTime = Date.now();\n const appLogger = getAppLogger(configuration);\n\n appLogger('Dictionaries:', { isVerbose: true });\n\n // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n const resolvedPlugins = await Promise.all(plugins ?? []);\n\n const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n (plugin) => plugin.loadDictionaries\n );\n\n logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));\n\n const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n async (plugin) => {\n try {\n const res = await plugin.loadDictionaries?.({\n configuration,\n });\n\n return (res as Dictionary[] | undefined) ?? [];\n } catch (error) {\n logger.setPluginError(error as Error, plugin.name);\n\n return [];\n }\n }\n );\n\n const pluginDictionaries: Dictionary[] = await Promise.all(\n loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n )\n .then((dictionaries) => dictionaries.flat())\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n logger.setPluginTotal(pluginDictionaries.length);\n logger.setPluginDone(pluginDictionaries.length);\n\n const pluginDictionariesTime = Date.now();\n\n const files = Array.isArray(contentDeclarationsPaths)\n ? contentDeclarationsPaths\n : [contentDeclarationsPaths];\n\n const localDictionaries: Dictionary[] = await loadContentDeclarations(\n files,\n configuration,\n setLoadDictionariesStatus\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n const localDictionariesTime = Date.now();\n\n const localDictionariesStatus = localDictionaries.map(\n (dictionary) =>\n ({\n dictionaryKey: dictionary.key,\n type: 'local',\n status: 'built',\n }) as const\n );\n\n setLoadDictionariesStatus(localDictionariesStatus);\n\n const hasRemoteDictionaries = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n if (hasRemoteDictionaries) {\n // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n logger.setExpectRemote(true);\n }\n\n let remoteDictionaries: Dictionary[] = [];\n\n if (hasRemoteDictionaries) {\n remoteDictionaries = await loadRemoteDictionaries(\n configuration,\n setLoadDictionariesStatus,\n {\n onStartRemoteCheck: () => logger.startRemoteCheck(),\n onStopRemoteCheck: () => logger.stopRemoteCheck(),\n onError: (e) => logger.setRemoteError(e),\n }\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n }\n\n const remoteDictionariesTime = Date.now();\n\n // Stop spinner and show final progress line(s)\n logger.finish();\n\n printSummary(configuration);\n\n return {\n localDictionaries,\n remoteDictionaries,\n pluginDictionaries,\n time: {\n localDictionaries: localDictionariesTime - pluginDictionariesTime,\n remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -40,7 +40,7 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
40
40
|
type: "remote",
|
|
41
41
|
status: "imported"
|
|
42
42
|
})));
|
|
43
|
-
const orderedDistantDictionaryKeys = dictionariesIdToFetch.map(([, data]) => data.key).sort(require_utils_sortAlphabetically.sortAlphabetically);
|
|
43
|
+
const orderedDistantDictionaryKeys = [...new Set(dictionariesIdToFetch.map(([, data]) => data.key))].sort(require_utils_sortAlphabetically.sortAlphabetically);
|
|
44
44
|
if (orderedDistantDictionaryKeys.length > 0) onStatusUpdate?.(orderedDistantDictionaryKeys.map((key) => ({
|
|
45
45
|
dictionaryKey: key,
|
|
46
46
|
type: "remote",
|
|
@@ -48,7 +48,8 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
48
48
|
})));
|
|
49
49
|
const distantDictionariesData = await require_fetchDistantDictionaries.fetchDistantDictionaries({ dictionaryKeys: orderedDistantDictionaryKeys }, onStatusUpdate);
|
|
50
50
|
const distantDictionaries = formatDistantDictionaries(distantDictionariesData);
|
|
51
|
-
|
|
51
|
+
const fetchedDictionaryIds = new Set(distantDictionaries.map((dictionary) => dictionary.id));
|
|
52
|
+
return [...cachedDictionaries.filter((dictionary) => !fetchedDictionaryIds.has(dictionary.id)), ...distantDictionaries];
|
|
52
53
|
} catch (error) {
|
|
53
54
|
options?.onError?.(error);
|
|
54
55
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadRemoteDictionaries.cjs","names":["sortAlphabetically","fetchDistantDictionaries"],"sources":["../../../src/loadDictionaries/loadRemoteDictionaries.ts"],"sourcesContent":["import { createIntlayerCMS } from '@intlayer/api';\nimport { dictionaryEndpoint } from '@intlayer/api/dictionary';\n// @ts-ignore @intlayer/backend is not build yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getRemoteDictionaries } from '@intlayer/remote-dictionaries-entry';\nimport type {\n Dictionary,\n DictionaryId,\n DictionaryKey,\n} from '@intlayer/types/dictionary';\nimport { fetchDistantDictionaries } from '../fetchDistantDictionaries';\nimport { sortAlphabetically } from '../utils/sortAlphabetically';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport const formatDistantDictionaries = (\n dictionaries: (DictionaryAPI | Dictionary)[]\n): Dictionary[] =>\n dictionaries.map((dict) => ({\n ...dict,\n localId: `${dict.key}::remote::${dict.id}`,\n location: 'remote' as const,\n }));\n\nexport const loadRemoteDictionaries = async (\n configuration = getConfiguration(),\n onStatusUpdate?: (status: DictionariesStatus[]) => void,\n options?: {\n onStartRemoteCheck?: () => void;\n onStopRemoteCheck?: () => void;\n onError?: (error: Error) => void;\n }\n): Promise<Dictionary[]> => {\n const { editor } = configuration;\n const remoteDictionariesRecord = getRemoteDictionaries(configuration);\n\n const hasRemoteDictionaries = Boolean(editor.clientId && editor.clientSecret);\n\n if (!hasRemoteDictionaries) return [];\n\n try {\n options?.onStartRemoteCheck?.();\n\n const dictionary = dictionaryEndpoint(createIntlayerCMS(configuration));\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await dictionary.getDictionariesUpdateTimestamp();\n\n const distantDictionaryUpdateTimeStamp: Record<\n DictionaryId,\n { key: DictionaryKey; updatedAt: number }\n > | null = getDictionariesKeysResult.data;\n\n if (!distantDictionaryUpdateTimeStamp) {\n throw new Error('No distant dictionaries found');\n }\n\n const dictionariesIdToFetch = Object.entries(\n distantDictionaryUpdateTimeStamp\n ).filter(([dictionaryId, data]) => {\n // If remote doesn't provide updatedAt, fetch to be safe\n if (!data.updatedAt) return true;\n\n // If no local cache exists, fetch\n const local: Dictionary | undefined = remoteDictionariesRecord[\n data.key\n ]?.find((dictionary) => dictionary.id === dictionaryId);\n if (!local) return true;\n\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // If local timestamp missing or older than remote, fetch\n if (typeof localUpdatedAt !== 'number') return true;\n\n return data.updatedAt > localUpdatedAt;\n });\n\n const flatRemoteDictionariesRecord: DictionaryAPI[] = Object.values(\n remoteDictionariesRecord\n ).flat();\n\n const cachedDictionaries: Dictionary[] =\n flatRemoteDictionariesRecord.filter((dictionary) => {\n const remoteUpdatedAt =\n distantDictionaryUpdateTimeStamp[dictionary.id!].updatedAt;\n\n const localUpdatedAtRaw = dictionary.updatedAt;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // Consider as cached/imported when local exists and is up-to-date or newer\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n });\n\n // Report cached as already imported\n if (cachedDictionaries.length > 0) {\n onStatusUpdate?.(\n cachedDictionaries.map((dictionary) => ({\n dictionaryKey: dictionary.key,\n type: 'remote',\n status: 'imported',\n }))\n );\n }\n\n const orderedDistantDictionaryKeys =
|
|
1
|
+
{"version":3,"file":"loadRemoteDictionaries.cjs","names":["sortAlphabetically","fetchDistantDictionaries"],"sources":["../../../src/loadDictionaries/loadRemoteDictionaries.ts"],"sourcesContent":["import { createIntlayerCMS } from '@intlayer/api';\nimport { dictionaryEndpoint } from '@intlayer/api/dictionary';\n// @ts-ignore @intlayer/backend is not build yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getRemoteDictionaries } from '@intlayer/remote-dictionaries-entry';\nimport type {\n Dictionary,\n DictionaryId,\n DictionaryKey,\n} from '@intlayer/types/dictionary';\nimport { fetchDistantDictionaries } from '../fetchDistantDictionaries';\nimport { sortAlphabetically } from '../utils/sortAlphabetically';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport const formatDistantDictionaries = (\n dictionaries: (DictionaryAPI | Dictionary)[]\n): Dictionary[] =>\n dictionaries.map((dict) => ({\n ...dict,\n localId: `${dict.key}::remote::${dict.id}`,\n location: 'remote' as const,\n }));\n\nexport const loadRemoteDictionaries = async (\n configuration = getConfiguration(),\n onStatusUpdate?: (status: DictionariesStatus[]) => void,\n options?: {\n onStartRemoteCheck?: () => void;\n onStopRemoteCheck?: () => void;\n onError?: (error: Error) => void;\n }\n): Promise<Dictionary[]> => {\n const { editor } = configuration;\n const remoteDictionariesRecord = getRemoteDictionaries(configuration);\n\n const hasRemoteDictionaries = Boolean(editor.clientId && editor.clientSecret);\n\n if (!hasRemoteDictionaries) return [];\n\n try {\n options?.onStartRemoteCheck?.();\n\n const dictionary = dictionaryEndpoint(createIntlayerCMS(configuration));\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await dictionary.getDictionariesUpdateTimestamp();\n\n const distantDictionaryUpdateTimeStamp: Record<\n DictionaryId,\n { key: DictionaryKey; updatedAt: number }\n > | null = getDictionariesKeysResult.data;\n\n if (!distantDictionaryUpdateTimeStamp) {\n throw new Error('No distant dictionaries found');\n }\n\n const dictionariesIdToFetch = Object.entries(\n distantDictionaryUpdateTimeStamp\n ).filter(([dictionaryId, data]) => {\n // If remote doesn't provide updatedAt, fetch to be safe\n if (!data.updatedAt) return true;\n\n // If no local cache exists, fetch\n const local: Dictionary | undefined = remoteDictionariesRecord[\n data.key\n ]?.find((dictionary) => dictionary.id === dictionaryId);\n if (!local) return true;\n\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // If local timestamp missing or older than remote, fetch\n if (typeof localUpdatedAt !== 'number') return true;\n\n return data.updatedAt > localUpdatedAt;\n });\n\n const flatRemoteDictionariesRecord: DictionaryAPI[] = Object.values(\n remoteDictionariesRecord\n ).flat();\n\n const cachedDictionaries: Dictionary[] =\n flatRemoteDictionariesRecord.filter((dictionary) => {\n const remoteUpdatedAt =\n distantDictionaryUpdateTimeStamp[dictionary.id!].updatedAt;\n\n const localUpdatedAtRaw = dictionary.updatedAt;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // Consider as cached/imported when local exists and is up-to-date or newer\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n });\n\n // Report cached as already imported\n if (cachedDictionaries.length > 0) {\n onStatusUpdate?.(\n cachedDictionaries.map((dictionary) => ({\n dictionaryKey: dictionary.key,\n type: 'remote',\n status: 'imported',\n }))\n );\n }\n\n // Several qualified dictionaries can share a key, so keys are deduplicated:\n // one request per key already returns all of its siblings.\n const orderedDistantDictionaryKeys = [\n ...new Set(dictionariesIdToFetch.map(([, data]) => data.key)),\n ].sort(sortAlphabetically);\n\n // Report pending for keys to be fetched so totals are visible immediately\n if (orderedDistantDictionaryKeys.length > 0) {\n onStatusUpdate?.(\n orderedDistantDictionaryKeys.map((key) => ({\n dictionaryKey: key,\n type: 'remote',\n status: 'pending',\n }))\n );\n }\n\n const distantDictionariesData = await fetchDistantDictionaries(\n {\n dictionaryKeys: orderedDistantDictionaryKeys,\n },\n onStatusUpdate\n );\n\n const distantDictionaries: Dictionary[] = formatDistantDictionaries(\n distantDictionariesData\n );\n\n // Fetching by key also returns the up-to-date siblings of a stale\n // dictionary, so drop the cached copies the remote just sent back.\n const fetchedDictionaryIds = new Set(\n distantDictionaries.map((dictionary) => dictionary.id)\n );\n\n const notRefetchedCachedDictionaries = cachedDictionaries.filter(\n (dictionary) => !fetchedDictionaryIds.has(dictionary.id)\n );\n\n return [...notRefetchedCachedDictionaries, ...distantDictionaries];\n } catch (error) {\n options?.onError?.(error as Error);\n return [];\n } finally {\n options?.onStopRemoteCheck?.();\n }\n};\n"],"mappings":";;;;;;;;;AAeA,MAAa,6BACX,iBAEA,aAAa,KAAK,UAAU;CAC1B,GAAG;CACH,SAAS,GAAG,KAAK,IAAI,YAAY,KAAK;CACtC,UAAU;AACZ,EAAE;AAEJ,MAAa,yBAAyB,OACpC,4DAAiC,GACjC,gBACA,YAK0B;CAC1B,MAAM,EAAE,WAAW;CACnB,MAAM,0FAAiD,aAAa;CAIpE,IAAI,CAF0B,QAAQ,OAAO,YAAY,OAAO,YAEvC,GAAG,OAAO,CAAC;CAEpC,IAAI;EACF,SAAS,qBAAqB;EAQ9B,MAAM,oCAGK,4FAT6C,aAAa,CAIpD,CAAC,CAAC,+BAA+B,EAKd,CAAC;EAErC,IAAI,CAAC,kCACH,MAAM,IAAI,MAAM,+BAA+B;EAGjD,MAAM,wBAAwB,OAAO,QACnC,gCACF,CAAC,CAAC,QAAQ,CAAC,cAAc,UAAU;GAEjC,IAAI,CAAC,KAAK,WAAW,OAAO;GAG5B,MAAM,QAAgC,yBACpC,KAAK,IACN,EAAE,MAAM,eAAe,WAAW,OAAO,YAAY;GACtD,IAAI,CAAC,OAAO,OAAO;GAEnB,MAAM,oBAAqB,OAAe;GAK1C,MAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,CAAC,CAAC,QAAQ,IACpC;GAGR,IAAI,OAAO,mBAAmB,UAAU,OAAO;GAE/C,OAAO,KAAK,YAAY;EAC1B,CAAC;EAMD,MAAM,qBAJgD,OAAO,OAC3D,wBACF,CAAC,CAAC,KAG2B,CAAC,CAAC,QAAQ,eAAe;GAClD,MAAM,kBACJ,iCAAiC,WAAW,GAAI,CAAC;GAEnD,MAAM,oBAAoB,WAAW;GAErC,MAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,CAAC,CAAC,QAAQ,IACpC;GAGR,OACE,OAAO,mBAAmB,YAC1B,OAAO,oBAAoB,YAC3B,kBAAkB;EAEtB,CAAC;EAGH,IAAI,mBAAmB,SAAS,GAC9B,iBACE,mBAAmB,KAAK,gBAAgB;GACtC,eAAe,WAAW;GAC1B,MAAM;GACN,QAAQ;EACV,EAAE,CACJ;EAKF,MAAM,+BAA+B,CACnC,GAAG,IAAI,IAAI,sBAAsB,KAAK,GAAG,UAAU,KAAK,GAAG,CAAC,CAC9D,CAAC,CAAC,KAAKA,mDAAkB;EAGzB,IAAI,6BAA6B,SAAS,GACxC,iBACE,6BAA6B,KAAK,SAAS;GACzC,eAAe;GACf,MAAM;GACN,QAAQ;EACV,EAAE,CACJ;EAGF,MAAM,0BAA0B,MAAMC,0DACpC,EACE,gBAAgB,6BAClB,GACA,cACF;EAEA,MAAM,sBAAoC,0BACxC,uBACF;EAIA,MAAM,uBAAuB,IAAI,IAC/B,oBAAoB,KAAK,eAAe,WAAW,EAAE,CACvD;EAMA,OAAO,CAAC,GAJ+B,mBAAmB,QACvD,eAAe,CAAC,qBAAqB,IAAI,WAAW,EAAE,CAGjB,GAAG,GAAG,mBAAmB;CACnE,SAAS,OAAO;EACd,SAAS,UAAU,KAAc;EACjC,OAAO,CAAC;CACV,UAAU;EACR,SAAS,oBAAoB;CAC/B;AACF"}
|
|
@@ -21,6 +21,7 @@ var DictionariesLogger = class {
|
|
|
21
21
|
remoteError;
|
|
22
22
|
pluginTotal = 0;
|
|
23
23
|
pluginDone = 0;
|
|
24
|
+
pluginNames = [];
|
|
24
25
|
pluginError;
|
|
25
26
|
constructor() {
|
|
26
27
|
this.prefix = (0, _intlayer_config_logger.getPrefix)(_intlayer_config_built.log?.prefix) ?? "";
|
|
@@ -71,6 +72,18 @@ var DictionariesLogger = class {
|
|
|
71
72
|
this.stopRemoteCheck();
|
|
72
73
|
this.render();
|
|
73
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Register the names of the plugins providing dictionaries.
|
|
77
|
+
* They are displayed next to the plugin progress counters, e.g.
|
|
78
|
+
* `Plugin content: 6/6 (sync-json, load-po)`.
|
|
79
|
+
*
|
|
80
|
+
* @param names - Names of the plugins exposing a `loadDictionaries` hook
|
|
81
|
+
*/
|
|
82
|
+
setPluginNames(names) {
|
|
83
|
+
if (this.isFinished) return;
|
|
84
|
+
this.pluginNames = names.filter((name) => Boolean(name));
|
|
85
|
+
this.render();
|
|
86
|
+
}
|
|
74
87
|
setPluginTotal(total) {
|
|
75
88
|
if (this.isFinished) return;
|
|
76
89
|
this.pluginTotal = total;
|
|
@@ -82,9 +95,16 @@ var DictionariesLogger = class {
|
|
|
82
95
|
this.pluginDone = done;
|
|
83
96
|
this.render();
|
|
84
97
|
}
|
|
85
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Flag the plugin line as errored.
|
|
100
|
+
*
|
|
101
|
+
* @param error - Error thrown while loading the plugin dictionaries
|
|
102
|
+
* @param pluginName - Name of the plugin that threw, prefixed to the message
|
|
103
|
+
*/
|
|
104
|
+
setPluginError(error, pluginName) {
|
|
86
105
|
if (this.isFinished) return;
|
|
87
|
-
|
|
106
|
+
const errorMessage = (0, _intlayer_config_utils.extractErrorMessage)(error);
|
|
107
|
+
this.pluginError = pluginName ? `${pluginName}: ${errorMessage}` : errorMessage;
|
|
88
108
|
this.render();
|
|
89
109
|
}
|
|
90
110
|
render() {
|
|
@@ -101,9 +121,12 @@ var DictionariesLogger = class {
|
|
|
101
121
|
else if (remoteTotal === 0) lines.push(`${this.prefix} ${clock} Remote content: ${(0, _intlayer_config_logger.colorize)("Check server", _intlayer_config_colors.BLUE)}`);
|
|
102
122
|
else if (isRemoteDone) lines.push(`${this.prefix} ${_intlayer_config_logger.v} Remote content: ${(0, _intlayer_config_logger.colorize)(`${remoteDone}`, _intlayer_config_colors.GREEN)}${(0, _intlayer_config_logger.colorize)(`/${remoteTotal}`, _intlayer_config_colors.GREY)}`);
|
|
103
123
|
else lines.push(`${this.prefix} ${clock} Remote content: ${(0, _intlayer_config_logger.colorize)(`${remoteDone}`, _intlayer_config_colors.BLUE)}${(0, _intlayer_config_logger.colorize)(`/${remoteTotal}`, _intlayer_config_colors.GREY)}`);
|
|
104
|
-
if (pluginTotal > 0 || this.pluginError)
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
if (pluginTotal > 0 || this.pluginError) {
|
|
125
|
+
const pluginNamesSuffix = this.pluginNames.length > 0 ? (0, _intlayer_config_logger.colorize)(` (${this.pluginNames.join(", ")})`, _intlayer_config_colors.GREY) : "";
|
|
126
|
+
if (this.pluginError) lines.push(`${this.prefix} ${_intlayer_config_logger.x} Plugin content: ${(0, _intlayer_config_logger.colorize)(this.pluginError, _intlayer_config_colors.RED)}`);
|
|
127
|
+
else if (isPluginDone) lines.push(`${this.prefix} ${_intlayer_config_logger.v} Plugin content: ${(0, _intlayer_config_logger.colorize)(`${pluginDone}`, _intlayer_config_colors.GREEN)}${(0, _intlayer_config_logger.colorize)(`/${pluginTotal}`, _intlayer_config_colors.GREY)}${pluginNamesSuffix}`);
|
|
128
|
+
else lines.push(`${this.prefix} ${clock} Plugin content: ${(0, _intlayer_config_logger.colorize)(`${pluginDone}`, _intlayer_config_colors.BLUE)}${(0, _intlayer_config_logger.colorize)(`/${pluginTotal}`, _intlayer_config_colors.GREY)}${pluginNamesSuffix}`);
|
|
129
|
+
}
|
|
107
130
|
const currentState = lines.join("\n");
|
|
108
131
|
if (currentState === this.lastRenderedState) return;
|
|
109
132
|
this.lastRenderedState = currentState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.cjs","names":["spinnerFrames","log","ANSIColors","v","x"],"sources":["../../../src/loadDictionaries/log.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n getPrefix,\n spinnerFrames,\n v,\n x,\n} from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport class DictionariesLogger {\n private statuses: DictionariesStatus[] = [];\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 private remoteCheckInProgress = false;\n private expectRemote = false;\n private remoteError: string | undefined;\n private pluginTotal = 0;\n private pluginDone = 0;\n private pluginError: string | undefined;\n\n constructor() {\n this.prefix = getPrefix(log?.prefix) ?? '';\n }\n\n setExpectRemote(expect: boolean) {\n this.expectRemote = expect;\n }\n\n startRemoteCheck() {\n if (this.isFinished) return;\n this.remoteCheckInProgress = true;\n this.startSpinner();\n this.render();\n }\n\n stopRemoteCheck() {\n this.remoteCheckInProgress = false;\n }\n\n update(newStatuses: DictionariesStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) =>\n s.dictionaryKey === status.dictionaryKey && s.type === status.type\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n // If we expect remote fetch later, avoid rendering a local-only line first\n const { remoteTotal } = this.computeProgress();\n if (this.expectRemote && !this.remoteCheckInProgress && remoteTotal === 0) {\n // Do not start spinner or render yet; wait until remote check starts\n return;\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n // Render final state and keep it visible\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 public setRemoteError = (error?: Error) => {\n this.remoteError = extractErrorMessage(error);\n // Avoid rendering a transient remote-only line while the remote check flag is still true\n // Ensure local + remote are rendered together after a failure\n this.stopRemoteCheck();\n this.render();\n };\n\n setPluginTotal(total: number) {\n if (this.isFinished) return;\n this.pluginTotal = total;\n if (total > 0) {\n this.startSpinner();\n }\n this.render();\n }\n\n setPluginDone(done: number) {\n if (this.isFinished) return;\n this.pluginDone = done;\n this.render();\n }\n\n setPluginError(error?: Error) {\n if (this.isFinished) return;\n this.pluginError = extractErrorMessage(error);\n this.render();\n }\n\n private render() {\n const {\n localTotal,\n localDone,\n remoteTotal,\n remoteDone,\n pluginTotal,\n pluginDone,\n } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const clock = colorize(frame, ANSIColors.BLUE);\n const lines: string[] = [];\n\n const isLocalDone = localDone === localTotal;\n const isRemoteDone = remoteDone === remoteTotal;\n const isPluginDone = pluginDone === pluginTotal;\n\n const suppressLocalWhileCheckingRemote =\n this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0;\n\n if (!suppressLocalWhileCheckingRemote) {\n if (isLocalDone) {\n lines.push(\n `${this.prefix} ${v} Local content: ${colorize(`${localDone}`, ANSIColors.GREEN)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Local content: ${colorize(`${localDone}`, ANSIColors.BLUE)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Single remote line: show error, check, or progress counts\n if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {\n if (this.remoteError) {\n lines.push(\n `${this.prefix} ${x} Remote content: ${colorize(\n this.remoteError,\n ANSIColors.RED\n )}`\n );\n } else if (remoteTotal === 0) {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize('Check server', ANSIColors.BLUE)}`\n );\n } else if (isRemoteDone) {\n lines.push(\n `${this.prefix} ${v} Remote content: ${colorize(`${remoteDone}`, ANSIColors.GREEN)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize(`${remoteDone}`, ANSIColors.BLUE)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Plugin line: show error or progress counts\n if (pluginTotal > 0 || this.pluginError) {\n if (this.pluginError) {\n lines.push(\n `${this.prefix} ${x} Plugin content: ${colorize(\n this.pluginError,\n ANSIColors.RED\n )}`\n );\n } else if (isPluginDone) {\n lines.push(\n `${this.prefix} ${v} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.GREEN)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.BLUE)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Check if the state has changed to avoid duplicate rendering\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 localKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'local')\n .map((s) => s.dictionaryKey)\n );\n\n const localDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'local' && (s.status === 'built' || s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n const remoteKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'remote')\n .map((s) => s.dictionaryKey)\n );\n\n const remoteDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'remote' &&\n (s.status === 'fetched' ||\n s.status === 'imported' ||\n s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n return {\n localTotal: localKeys.size,\n localDone: localDoneKeys.size,\n remoteTotal: remoteKeys.size,\n remoteDone: remoteDoneKeys.size,\n pluginTotal: this.pluginTotal,\n pluginDone: this.pluginDone,\n } as const;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"log.cjs","names":["spinnerFrames","log","ANSIColors","v","x"],"sources":["../../../src/loadDictionaries/log.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n getPrefix,\n spinnerFrames,\n v,\n x,\n} from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport class DictionariesLogger {\n private statuses: DictionariesStatus[] = [];\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 private remoteCheckInProgress = false;\n private expectRemote = false;\n private remoteError: string | undefined;\n private pluginTotal = 0;\n private pluginDone = 0;\n private pluginNames: string[] = [];\n private pluginError: string | undefined;\n\n constructor() {\n this.prefix = getPrefix(log?.prefix) ?? '';\n }\n\n setExpectRemote(expect: boolean) {\n this.expectRemote = expect;\n }\n\n startRemoteCheck() {\n if (this.isFinished) return;\n this.remoteCheckInProgress = true;\n this.startSpinner();\n this.render();\n }\n\n stopRemoteCheck() {\n this.remoteCheckInProgress = false;\n }\n\n update(newStatuses: DictionariesStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) =>\n s.dictionaryKey === status.dictionaryKey && s.type === status.type\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n // If we expect remote fetch later, avoid rendering a local-only line first\n const { remoteTotal } = this.computeProgress();\n if (this.expectRemote && !this.remoteCheckInProgress && remoteTotal === 0) {\n // Do not start spinner or render yet; wait until remote check starts\n return;\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n // Render final state and keep it visible\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 public setRemoteError = (error?: Error) => {\n this.remoteError = extractErrorMessage(error);\n // Avoid rendering a transient remote-only line while the remote check flag is still true\n // Ensure local + remote are rendered together after a failure\n this.stopRemoteCheck();\n this.render();\n };\n\n /**\n * Register the names of the plugins providing dictionaries.\n * They are displayed next to the plugin progress counters, e.g.\n * `Plugin content: 6/6 (sync-json, load-po)`.\n *\n * @param names - Names of the plugins exposing a `loadDictionaries` hook\n */\n setPluginNames(names: string[]) {\n if (this.isFinished) return;\n // Guard against plugins declared without a name at runtime\n this.pluginNames = names.filter((name) => Boolean(name));\n this.render();\n }\n\n setPluginTotal(total: number) {\n if (this.isFinished) return;\n this.pluginTotal = total;\n if (total > 0) {\n this.startSpinner();\n }\n this.render();\n }\n\n setPluginDone(done: number) {\n if (this.isFinished) return;\n this.pluginDone = done;\n this.render();\n }\n\n /**\n * Flag the plugin line as errored.\n *\n * @param error - Error thrown while loading the plugin dictionaries\n * @param pluginName - Name of the plugin that threw, prefixed to the message\n */\n setPluginError(error?: Error, pluginName?: string) {\n if (this.isFinished) return;\n const errorMessage = extractErrorMessage(error);\n this.pluginError = pluginName\n ? `${pluginName}: ${errorMessage}`\n : errorMessage;\n this.render();\n }\n\n private render() {\n const {\n localTotal,\n localDone,\n remoteTotal,\n remoteDone,\n pluginTotal,\n pluginDone,\n } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const clock = colorize(frame, ANSIColors.BLUE);\n const lines: string[] = [];\n\n const isLocalDone = localDone === localTotal;\n const isRemoteDone = remoteDone === remoteTotal;\n const isPluginDone = pluginDone === pluginTotal;\n\n const suppressLocalWhileCheckingRemote =\n this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0;\n\n if (!suppressLocalWhileCheckingRemote) {\n if (isLocalDone) {\n lines.push(\n `${this.prefix} ${v} Local content: ${colorize(`${localDone}`, ANSIColors.GREEN)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Local content: ${colorize(`${localDone}`, ANSIColors.BLUE)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Single remote line: show error, check, or progress counts\n if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {\n if (this.remoteError) {\n lines.push(\n `${this.prefix} ${x} Remote content: ${colorize(\n this.remoteError,\n ANSIColors.RED\n )}`\n );\n } else if (remoteTotal === 0) {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize('Check server', ANSIColors.BLUE)}`\n );\n } else if (isRemoteDone) {\n lines.push(\n `${this.prefix} ${v} Remote content: ${colorize(`${remoteDone}`, ANSIColors.GREEN)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize(`${remoteDone}`, ANSIColors.BLUE)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Plugin line: show error or progress counts, suffixed by the plugin names\n if (pluginTotal > 0 || this.pluginError) {\n const pluginNamesSuffix =\n this.pluginNames.length > 0\n ? colorize(` (${this.pluginNames.join(', ')})`, ANSIColors.GREY)\n : '';\n\n if (this.pluginError) {\n lines.push(\n `${this.prefix} ${x} Plugin content: ${colorize(\n this.pluginError,\n ANSIColors.RED\n )}`\n );\n } else if (isPluginDone) {\n lines.push(\n `${this.prefix} ${v} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.GREEN)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.BLUE)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n }\n }\n\n // Check if the state has changed to avoid duplicate rendering\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 localKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'local')\n .map((s) => s.dictionaryKey)\n );\n\n const localDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'local' && (s.status === 'built' || s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n const remoteKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'remote')\n .map((s) => s.dictionaryKey)\n );\n\n const remoteDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'remote' &&\n (s.status === 'fetched' ||\n s.status === 'imported' ||\n s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n return {\n localTotal: localKeys.size,\n localDone: localDoneKeys.size,\n remoteTotal: remoteKeys.size,\n remoteDone: remoteDoneKeys.size,\n pluginTotal: this.pluginTotal,\n pluginDone: this.pluginDone,\n } as const;\n }\n}\n"],"mappings":";;;;;;;;;AAYA,IAAa,qBAAb,MAAgC;CAC9B,AAAQ,WAAiC,CAAC;CAC1C,AAAQ,eAAsC;CAC9C,AAAQ,eAAe;CACvB,AAAQ,gBAAgB;CACxB,AAAiB,gBAAgBA;CACjC,AAAQ,aAAa;CACrB,AAAiB;CACjB,AAAQ,oBAA4B;CACpC,AAAQ,wBAAwB;CAChC,AAAQ,eAAe;CACvB,AAAQ;CACR,AAAQ,cAAc;CACtB,AAAQ,aAAa;CACrB,AAAQ,cAAwB,CAAC;CACjC,AAAQ;CAER,cAAc;EACZ,KAAK,gDAAmBC,4BAAK,MAAM,KAAK;CAC1C;CAEA,gBAAgB,QAAiB;EAC/B,KAAK,eAAe;CACtB;CAEA,mBAAmB;EACjB,IAAI,KAAK,YAAY;EACrB,KAAK,wBAAwB;EAC7B,KAAK,aAAa;EAClB,KAAK,OAAO;CACd;CAEA,kBAAkB;EAChB,KAAK,wBAAwB;CAC/B;CAEA,OAAO,aAAmC;EACxC,IAAI,KAAK,YAAY;EACrB,KAAK,MAAM,UAAU,aAAa;GAChC,MAAM,QAAQ,KAAK,SAAS,WACzB,MACC,EAAE,kBAAkB,OAAO,iBAAiB,EAAE,SAAS,OAAO,IAClE;GACA,IAAI,SAAS,GACX,KAAK,SAAS,SAAS;QAEvB,KAAK,SAAS,KAAK,MAAM;EAE7B;EAGA,MAAM,EAAE,gBAAgB,KAAK,gBAAgB;EAC7C,IAAI,KAAK,gBAAgB,CAAC,KAAK,yBAAyB,gBAAgB,GAEtE;EAGF,KAAK,aAAa;EAClB,KAAK,OAAO;CACd;CAEA,SAAS;EACP,KAAK,aAAa;EAClB,KAAK,YAAY;EAEjB,KAAK,OAAO;CACd;CAEA,AAAQ,eAAe;EACrB,IAAI,KAAK,gBAAgB,KAAK,YAAY;EAC1C,KAAK,eAAe,kBAAkB;GACpC,KAAK,gBAAgB,KAAK,eAAe,KAAK,KAAK,cAAc;GACjE,KAAK,OAAO;EACd,GAAG,GAAG;CACR;CAEA,AAAQ,cAAc;EACpB,IAAI,CAAC,KAAK,cAAc;EACxB,cAAc,KAAK,YAAY;EAC/B,KAAK,eAAe;CACtB;CAEA,AAAO,kBAAkB,UAAkB;EACzC,KAAK,8DAAkC,KAAK;EAG5C,KAAK,gBAAgB;EACrB,KAAK,OAAO;CACd;;;;;;;;CASA,eAAe,OAAiB;EAC9B,IAAI,KAAK,YAAY;EAErB,KAAK,cAAc,MAAM,QAAQ,SAAS,QAAQ,IAAI,CAAC;EACvD,KAAK,OAAO;CACd;CAEA,eAAe,OAAe;EAC5B,IAAI,KAAK,YAAY;EACrB,KAAK,cAAc;EACnB,IAAI,QAAQ,GACV,KAAK,aAAa;EAEpB,KAAK,OAAO;CACd;CAEA,cAAc,MAAc;EAC1B,IAAI,KAAK,YAAY;EACrB,KAAK,aAAa;EAClB,KAAK,OAAO;CACd;;;;;;;CAQA,eAAe,OAAe,YAAqB;EACjD,IAAI,KAAK,YAAY;EACrB,MAAM,+DAAmC,KAAK;EAC9C,KAAK,cAAc,aACf,GAAG,WAAW,IAAI,iBAClB;EACJ,KAAK,OAAO;CACd;CAEA,AAAQ,SAAS;EACf,MAAM,EACJ,YACA,WACA,aACA,YACA,aACA,eACE,KAAK,gBAAgB;EAEzB,MAAM,QAAQ,KAAK,cAAc,KAAK;EACtC,MAAM,8CAAiB,OAAOC,wBAAW,IAAI;EAC7C,MAAM,QAAkB,CAAC;EAEzB,MAAM,cAAc,cAAc;EAClC,MAAM,eAAe,eAAe;EACpC,MAAM,eAAe,eAAe;EAKpC,IAAI,EAFF,KAAK,gBAAgB,KAAK,yBAAyB,gBAAgB,IAGnE,IAAI,aACF,MAAM,KACJ,GAAG,KAAK,OAAO,GAAGC,0BAAE,wDAA2B,GAAG,aAAaD,wBAAW,KAAK,0CAAa,IAAI,cAAcA,wBAAW,IAAI,GAC/H;OAEA,MAAM,KACJ,GAAG,KAAK,OAAO,GAAG,MAAM,wDAA2B,GAAG,aAAaA,wBAAW,IAAI,0CAAa,IAAI,cAAcA,wBAAW,IAAI,GAClI;EAKJ,IAAI,cAAc,KAAK,KAAK,yBAAyB,KAAK,aACxD,IAAI,KAAK,aACP,MAAM,KACJ,GAAG,KAAK,OAAO,GAAGE,0BAAE,yDAClB,KAAK,aACLF,wBAAW,GACb,GACF;OACK,IAAI,gBAAgB,GACzB,MAAM,KACJ,GAAG,KAAK,OAAO,GAAG,MAAM,yDAA4B,gBAAgBA,wBAAW,IAAI,GACrF;OACK,IAAI,cACT,MAAM,KACJ,GAAG,KAAK,OAAO,GAAGC,0BAAE,yDAA4B,GAAG,cAAcD,wBAAW,KAAK,0CAAa,IAAI,eAAeA,wBAAW,IAAI,GAClI;OAEA,MAAM,KACJ,GAAG,KAAK,OAAO,GAAG,MAAM,yDAA4B,GAAG,cAAcA,wBAAW,IAAI,0CAAa,IAAI,eAAeA,wBAAW,IAAI,GACrI;EAKJ,IAAI,cAAc,KAAK,KAAK,aAAa;GACvC,MAAM,oBACJ,KAAK,YAAY,SAAS,0CACb,KAAK,KAAK,YAAY,KAAK,IAAI,EAAE,IAAIA,wBAAW,IAAI,IAC7D;GAEN,IAAI,KAAK,aACP,MAAM,KACJ,GAAG,KAAK,OAAO,GAAGE,0BAAE,yDAClB,KAAK,aACLF,wBAAW,GACb,GACF;QACK,IAAI,cACT,MAAM,KACJ,GAAG,KAAK,OAAO,GAAGC,0BAAE,yDAA4B,GAAG,cAAcD,wBAAW,KAAK,0CAAa,IAAI,eAAeA,wBAAW,IAAI,IAAI,mBACtI;QAEA,MAAM,KACJ,GAAG,KAAK,OAAO,GAAG,MAAM,yDAA4B,GAAG,cAAcA,wBAAW,IAAI,0CAAa,IAAI,eAAeA,wBAAW,IAAI,IAAI,mBACzI;EAEJ;EAGA,MAAM,eAAe,MAAM,KAAK,IAAI;EACpC,IAAI,iBAAiB,KAAK,mBACxB;EAEF,KAAK,oBAAoB;EAEzB,IAAI,KAAK,gBAAgB,GACvB,QAAQ,OAAO,MAAM,QAAQ,KAAK,cAAc,EAAE;EAGpD,MAAM,oBAAoB,KAAK,IAAI,KAAK,eAAe,MAAM,MAAM;EACnE,KAAK,IAAI,IAAI,GAAG,IAAI,mBAAmB,KAAK;GAC1C,QAAQ,OAAO,MAAM,SAAS;GAC9B,MAAM,OAAO,MAAM;GACnB,IAAI,SAAS,QACX,QAAQ,OAAO,MAAM,IAAI;GAE3B,QAAQ,OAAO,MAAM,IAAI;EAC3B;EAEA,KAAK,gBAAgB,MAAM;CAC7B;CAEA,AAAQ,kBAAkB;EACxB,MAAM,YAAY,IAAI,IACpB,KAAK,SACF,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CACjC,KAAK,MAAM,EAAE,aAAa,CAC/B;EAEA,MAAM,gBAAgB,IAAI,IACxB,KAAK,SACF,QACE,MACC,EAAE,SAAS,YAAY,EAAE,WAAW,WAAW,EAAE,WAAW,QAChE,CAAC,CACA,KAAK,MAAM,EAAE,aAAa,CAC/B;EAEA,MAAM,aAAa,IAAI,IACrB,KAAK,SACF,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC,CAClC,KAAK,MAAM,EAAE,aAAa,CAC/B;EAEA,MAAM,iBAAiB,IAAI,IACzB,KAAK,SACF,QACE,MACC,EAAE,SAAS,aACV,EAAE,WAAW,aACZ,EAAE,WAAW,cACb,EAAE,WAAW,QACnB,CAAC,CACA,KAAK,MAAM,EAAE,aAAa,CAC/B;EAEA,OAAO;GACL,YAAY,UAAU;GACtB,WAAW,cAAc;GACzB,aAAa,WAAW;GACxB,YAAY,eAAe;GAC3B,aAAa,KAAK;GAClB,YAAY,KAAK;EACnB;CACF;AACF"}
|
|
@@ -31,7 +31,7 @@ const prepareIntlayer = async (configuration, options) => {
|
|
|
31
31
|
const sentinelPath = (0, node_path.join)(configuration.system.cacheDir, "intlayer-prepared.lock");
|
|
32
32
|
const versionCache = (0, _intlayer_config_utils.cacheDisk)(configuration, ["intlayer-version"]);
|
|
33
33
|
const intlayerCacheVersion = await versionCache.get();
|
|
34
|
-
const isCorrectVersion = Boolean(intlayerCacheVersion
|
|
34
|
+
const isCorrectVersion = Boolean(intlayerCacheVersion === void 0 || intlayerCacheVersion === _intlayer_config_package_json.default.version);
|
|
35
35
|
const isConfigSimilar = await require_writeConfiguration_index.isCachedConfigurationUpToDate(configuration);
|
|
36
36
|
const dictionariesWithStats = await require_listDictionariesPath.listDictionariesWithStats(configuration);
|
|
37
37
|
let isDictionaryChanged = false;
|
|
@@ -45,8 +45,12 @@ const prepareIntlayer = async (configuration, options) => {
|
|
|
45
45
|
forceRun: !isCorrectVersion || !isConfigSimilar || isDictionaryChanged || hasPluginLoadDictionaries,
|
|
46
46
|
...options ?? {}
|
|
47
47
|
};
|
|
48
|
-
await require_utils_runOnce.runOnce(sentinelPath, async () => {
|
|
49
|
-
|
|
48
|
+
await require_utils_runOnce.runOnce(sentinelPath, async ({ renewLock }) => {
|
|
49
|
+
const isCorrectVersionUnderLock = await versionCache.get() === _intlayer_config_package_json.default.version;
|
|
50
|
+
if (clean || !isCorrectVersionUnderLock) {
|
|
51
|
+
await require_cleanOutputDir.cleanOutputDir(configuration);
|
|
52
|
+
await renewLock();
|
|
53
|
+
}
|
|
50
54
|
await versionCache.set(_intlayer_config_package_json.default.version);
|
|
51
55
|
const preparationStartMs = Date.now();
|
|
52
56
|
appLogger(["Preparing Intlayer", (0, _intlayer_config_logger.colorize)(`(v${_intlayer_config_package_json.default.version})`, _intlayer_config_colors.GREY_DARK)]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","isCachedConfigurationUpToDate","listDictionariesWithStats","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { cacheDisk } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary';\nimport { cleanOutputDir } from './cleanOutputDir';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { listDictionariesWithStats } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport {\n isCachedConfigurationUpToDate,\n writeConfiguration,\n} from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\n env?: 'prod' | 'dev';\n format?: ('cjs' | 'esm')[];\n forceRun?: boolean;\n cacheTimeoutMs?: number;\n onIsCached?: () => void | Promise<void>;\n};\n\nconst DEFAULT_PREPARE_INTLAYER_OPTIONS = {\n clean: false,\n env: 'dev',\n format: ['cjs', 'esm'],\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n} satisfies PrepareIntlayerOptions;\n\nexport const prepareIntlayer = async (\n configuration: IntlayerConfig,\n options?: PrepareIntlayerOptions\n) => {\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n // Clean output dir if the intlayer version has changed\n const versionCache = cacheDisk(configuration, ['intlayer-version']);\n const intlayerCacheVersion = await versionCache.get();\n const isCorrectVersion = Boolean(\n intlayerCacheVersion && intlayerCacheVersion === packageJson.version\n );\n\n const isConfigSimilar = await isCachedConfigurationUpToDate(configuration);\n\n // Check if any dictionary has been changed to force a new rebuild\n const dictionariesWithStats = await listDictionariesWithStats(configuration);\n let isDictionaryChanged = false;\n try {\n // Try catch as sentinel file may not exist yet\n const sentinelStats = await stat(sentinelPath);\n isDictionaryChanged = dictionariesWithStats.some(\n (dictionary) =>\n dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime()\n );\n } catch {}\n\n const resolvedPlugins = await Promise.all(configuration.plugins ?? []);\n const hasPluginLoadDictionaries = resolvedPlugins.some((plugin) =>\n Boolean(plugin.loadDictionaries)\n ); // Disable cache if any plugin because it can have custom behavior\n\n const { clean, format, forceRun, onIsCached, cacheTimeoutMs, env } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun:\n !isCorrectVersion ||\n !isConfigSimilar ||\n isDictionaryChanged ||\n hasPluginLoadDictionaries,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\n // comment because of issue with next and webpack\n // await checkVersionsConsistency(configuration);\n\n if (clean || !isCorrectVersion) {\n await cleanOutputDir(configuration);\n }\n\n await versionCache.set(packageJson.version);\n\n const preparationStartMs = Date.now();\n\n appLogger([\n 'Preparing Intlayer',\n colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK),\n ]);\n\n await writeConfiguration(configuration);\n\n const configurationWrittenTime = Date.now();\n\n appLogger(\n [\n 'Configuration written',\n colorize(\n `(${configurationWrittenTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n const contentDeclarationPaths = dictionariesWithStats.map(\n (dictionary) => dictionary.path\n );\n\n const dictionaries = await loadDictionaries(\n contentDeclarationPaths,\n configuration\n );\n\n const dictionariesLoadedTime = Date.now();\n\n appLogger(\n [\n 'Content loaded',\n colorize(\n [\n dictionaries.remoteDictionaries.length +\n dictionaries.pluginDictionaries.length >\n 0\n ? [\n `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,\n dictionaries.localDictionaries.length > 0\n ? ` - Local: ${dictionaries.time.localDictionaries}ms`\n : '',\n dictionaries.remoteDictionaries.length > 0\n ? ` - Remote: ${dictionaries.time.remoteDictionaries}ms`\n : '',\n dictionaries.pluginDictionaries.length > 0\n ? ` - Plugin: ${dictionaries.time.pluginDictionaries}ms`\n : '',\n `)`,\n ].join('')\n : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`,\n ].join(''),\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Build local dictionaries\n const dictionariesOutput = await buildDictionary(\n [\n ...dictionaries.localDictionaries,\n ...dictionaries.remoteDictionaries,\n ...dictionaries.pluginDictionaries,\n ],\n configuration,\n { formats: format, importOtherDictionaries: false, env }\n );\n\n // Write remote dictionaries\n // Used as cache for next fetch\n await writeRemoteDictionary(\n dictionaries.remoteDictionaries,\n configuration\n );\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, configuration);\n\n await createDictionaryEntryPoint(configuration, {\n formats: options?.format,\n });\n\n const dictionariesBuiltTime = Date.now();\n\n appLogger([\n 'Dictionaries built',\n colorize(\n `(${dictionariesBuiltTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ]);\n\n await createModuleAugmentation(configuration);\n\n const moduleAugmentationBuiltTime = Date.now();\n\n appLogger(\n [\n 'Module augmentation built',\n colorize(\n `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Plugin transformation\n // Allow plugins to post-process the final build output (e.g., write back ICU JSON)\n for await (const plugin of configuration.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n try {\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\n });\n } catch (error) {\n // A failing write-back (e.g. transient network error on a remote\n // target) must not invalidate the dictionaries already built.\n appLogger(\n [\n `Plugin ${plugin.name} afterBuild failed:`,\n (error as Error).message,\n ],\n { level: 'error' }\n );\n }\n }\n\n const preparationElapsedMs = Date.now() - preparationStartMs;\n appLogger(\n [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)],\n {\n level: 'info',\n isVerbose: true,\n }\n );\n },\n {\n forceRun,\n onIsCached,\n cacheTimeoutMs,\n }\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","isCachedConfigurationUpToDate","listDictionariesWithStats","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { cacheDisk } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary';\nimport { cleanOutputDir } from './cleanOutputDir';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { listDictionariesWithStats } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport {\n isCachedConfigurationUpToDate,\n writeConfiguration,\n} from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\n env?: 'prod' | 'dev';\n format?: ('cjs' | 'esm')[];\n forceRun?: boolean;\n cacheTimeoutMs?: number;\n onIsCached?: () => void | Promise<void>;\n};\n\nconst DEFAULT_PREPARE_INTLAYER_OPTIONS = {\n clean: false,\n env: 'dev',\n format: ['cjs', 'esm'],\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n} satisfies PrepareIntlayerOptions;\n\nexport const prepareIntlayer = async (\n configuration: IntlayerConfig,\n options?: PrepareIntlayerOptions\n) => {\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n // Clean output dir if the intlayer version has changed\n const versionCache = cacheDisk(configuration, ['intlayer-version']);\n const intlayerCacheVersion = await versionCache.get();\n const isCorrectVersion = Boolean(\n intlayerCacheVersion === undefined ||\n intlayerCacheVersion === packageJson.version\n );\n\n const isConfigSimilar = await isCachedConfigurationUpToDate(configuration);\n\n // Check if any dictionary has been changed to force a new rebuild\n const dictionariesWithStats = await listDictionariesWithStats(configuration);\n let isDictionaryChanged = false;\n try {\n // Try catch as sentinel file may not exist yet\n const sentinelStats = await stat(sentinelPath);\n isDictionaryChanged = dictionariesWithStats.some(\n (dictionary) =>\n dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime()\n );\n } catch {}\n\n const resolvedPlugins = await Promise.all(configuration.plugins ?? []);\n const hasPluginLoadDictionaries = resolvedPlugins.some((plugin) =>\n Boolean(plugin.loadDictionaries)\n ); // Disable cache if any plugin because it can have custom behavior\n\n const { clean, format, forceRun, onIsCached, cacheTimeoutMs, env } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun:\n !isCorrectVersion ||\n !isConfigSimilar ||\n isDictionaryChanged ||\n hasPluginLoadDictionaries,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async ({ renewLock }) => {\n // comment because of issue with next and webpack\n // await checkVersionsConsistency(configuration);\n\n // Re-read the cached version now that the lock is held: another process\n // may have upgraded the output directory while this call was queued, in\n // which case cleaning it would throw away a build that just completed.\n const isCorrectVersionUnderLock =\n (await versionCache.get()) === packageJson.version;\n\n if (clean || !isCorrectVersionUnderLock) {\n await cleanOutputDir(configuration);\n // `cleanOutputDir` wipes the cache directory the sentinel lives in.\n // Re-create it immediately, otherwise a concurrent process (e.g. the\n // `intlayer watch` CLI next to a dev server) sees no lock, starts its\n // own run, and cleans the output directory while this one writes.\n await renewLock();\n }\n\n await versionCache.set(packageJson.version);\n\n const preparationStartMs = Date.now();\n\n appLogger([\n 'Preparing Intlayer',\n colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK),\n ]);\n\n await writeConfiguration(configuration);\n\n const configurationWrittenTime = Date.now();\n\n appLogger(\n [\n 'Configuration written',\n colorize(\n `(${configurationWrittenTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n const contentDeclarationPaths = dictionariesWithStats.map(\n (dictionary) => dictionary.path\n );\n\n const dictionaries = await loadDictionaries(\n contentDeclarationPaths,\n configuration\n );\n\n const dictionariesLoadedTime = Date.now();\n\n appLogger(\n [\n 'Content loaded',\n colorize(\n [\n dictionaries.remoteDictionaries.length +\n dictionaries.pluginDictionaries.length >\n 0\n ? [\n `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,\n dictionaries.localDictionaries.length > 0\n ? ` - Local: ${dictionaries.time.localDictionaries}ms`\n : '',\n dictionaries.remoteDictionaries.length > 0\n ? ` - Remote: ${dictionaries.time.remoteDictionaries}ms`\n : '',\n dictionaries.pluginDictionaries.length > 0\n ? ` - Plugin: ${dictionaries.time.pluginDictionaries}ms`\n : '',\n `)`,\n ].join('')\n : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`,\n ].join(''),\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Build local dictionaries\n const dictionariesOutput = await buildDictionary(\n [\n ...dictionaries.localDictionaries,\n ...dictionaries.remoteDictionaries,\n ...dictionaries.pluginDictionaries,\n ],\n configuration,\n { formats: format, importOtherDictionaries: false, env }\n );\n\n // Write remote dictionaries\n // Used as cache for next fetch\n await writeRemoteDictionary(\n dictionaries.remoteDictionaries,\n configuration\n );\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, configuration);\n\n await createDictionaryEntryPoint(configuration, {\n formats: options?.format,\n });\n\n const dictionariesBuiltTime = Date.now();\n\n appLogger([\n 'Dictionaries built',\n colorize(\n `(${dictionariesBuiltTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ]);\n\n await createModuleAugmentation(configuration);\n\n const moduleAugmentationBuiltTime = Date.now();\n\n appLogger(\n [\n 'Module augmentation built',\n colorize(\n `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Plugin transformation\n // Allow plugins to post-process the final build output (e.g., write back ICU JSON)\n for await (const plugin of configuration.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n try {\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\n });\n } catch (error) {\n // A failing write-back (e.g. transient network error on a remote\n // target) must not invalidate the dictionaries already built.\n appLogger(\n [\n `Plugin ${plugin.name} afterBuild failed:`,\n (error as Error).message,\n ],\n { level: 'error' }\n );\n }\n }\n\n const preparationElapsedMs = Date.now() - preparationStartMs;\n appLogger(\n [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)],\n {\n level: 'info',\n isVerbose: true,\n }\n );\n },\n {\n forceRun,\n onIsCached,\n cacheTimeoutMs,\n }\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
//#region src/utils/chunkArray.ts
|
|
4
|
+
/**
|
|
5
|
+
* Splits an array into consecutive chunks of at most `chunkSize` items.
|
|
6
|
+
*
|
|
7
|
+
* The last chunk holds the remainder and may be smaller. An empty input, or a
|
|
8
|
+
* `chunkSize` lower than 1, returns an empty list of chunks.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* chunkArray(['a', 'b', 'c', 'd', 'e'], 2); // [['a', 'b'], ['c', 'd'], ['e']]
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
const chunkArray = (items, chunkSize) => {
|
|
16
|
+
if (chunkSize < 1) return [];
|
|
17
|
+
const chunks = [];
|
|
18
|
+
for (let index = 0; index < items.length; index += chunkSize) chunks.push(items.slice(index, index + chunkSize));
|
|
19
|
+
return chunks;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.chunkArray = chunkArray;
|
|
24
|
+
//# sourceMappingURL=chunkArray.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunkArray.cjs","names":[],"sources":["../../../src/utils/chunkArray.ts"],"sourcesContent":["/**\n * Splits an array into consecutive chunks of at most `chunkSize` items.\n *\n * The last chunk holds the remainder and may be smaller. An empty input, or a\n * `chunkSize` lower than 1, returns an empty list of chunks.\n *\n * @example\n * ```ts\n * chunkArray(['a', 'b', 'c', 'd', 'e'], 2); // [['a', 'b'], ['c', 'd'], ['e']]\n * ```\n */\nexport const chunkArray = <T>(items: T[], chunkSize: number): T[][] => {\n if (chunkSize < 1) return [];\n\n const chunks: T[][] = [];\n\n for (let index = 0; index < items.length; index += chunkSize) {\n chunks.push(items.slice(index, index + chunkSize));\n }\n\n return chunks;\n};\n"],"mappings":";;;;;;;;;;;;;;AAWA,MAAa,cAAiB,OAAY,cAA6B;CACrE,IAAI,YAAY,GAAG,OAAO,CAAC;CAE3B,MAAM,SAAgB,CAAC;CAEvB,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,WACjD,OAAO,KAAK,MAAM,MAAM,OAAO,QAAQ,SAAS,CAAC;CAGnD,OAAO;AACT"}
|
package/dist/cjs/utils/index.cjs
CHANGED
|
@@ -5,6 +5,7 @@ const require_utils_getPathHash = require('./getPathHash.cjs');
|
|
|
5
5
|
const require_utils_formatter = require('./formatter.cjs');
|
|
6
6
|
const require_utils_autoDecorateContent = require('./autoDecorateContent.cjs');
|
|
7
7
|
const require_utils_buildComponentFilesList = require('./buildComponentFilesList.cjs');
|
|
8
|
+
const require_utils_chunkArray = require('./chunkArray.cjs');
|
|
8
9
|
const require_utils_splitTextByLine = require('./splitTextByLine.cjs');
|
|
9
10
|
const require_utils_getChunk = require('./getChunk.cjs');
|
|
10
11
|
const require_utils_chunkJSON = require('./chunkJSON.cjs');
|
|
@@ -24,6 +25,7 @@ exports.Queue = require_utils_pLimit.Queue;
|
|
|
24
25
|
exports.assembleJSON = require_utils_chunkJSON.assembleJSON;
|
|
25
26
|
exports.autoDecorateContent = require_utils_autoDecorateContent.autoDecorateContent;
|
|
26
27
|
exports.buildComponentFilesList = require_utils_buildComponentFilesList.buildComponentFilesList;
|
|
28
|
+
exports.chunkArray = require_utils_chunkArray.chunkArray;
|
|
27
29
|
exports.chunkJSON = require_utils_chunkJSON.chunkJSON;
|
|
28
30
|
exports.excludeObjectFormat = require_utils_reduceObjectFormat.excludeObjectFormat;
|
|
29
31
|
exports.formatLocale = require_utils_formatter.formatLocale;
|
|
@@ -2,92 +2,171 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
let node_fs_promises = require("node:fs/promises");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
|
+
let node_fs = require("node:fs");
|
|
5
6
|
let _intlayer_core_package_json = require("@intlayer/core/package.json");
|
|
6
7
|
_intlayer_core_package_json = require_runtime.__toESM(_intlayer_core_package_json);
|
|
7
8
|
|
|
8
9
|
//#region src/utils/runOnce.ts
|
|
9
|
-
const DEFAULT_RUN_ONCE_OPTIONS = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const DEFAULT_RUN_ONCE_OPTIONS = {
|
|
11
|
+
cacheTimeoutMs: 60 * 1e3,
|
|
12
|
+
lockWaitTimeoutMs: 300 * 1e3
|
|
13
|
+
};
|
|
14
|
+
/** Delay between two reads of a sentinel owned by another process. */
|
|
15
|
+
const LOCK_POLL_INTERVAL_MS = 50;
|
|
16
|
+
const delay = (durationMs) => new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
17
|
+
/**
|
|
18
|
+
* Sentinels owned by this process, released synchronously on exit so a crash or
|
|
19
|
+
* a Ctrl-C never leaves a `running` lock that would stall the next run.
|
|
20
|
+
*/
|
|
21
|
+
const ownedSentinelFilePaths = /* @__PURE__ */ new Set();
|
|
22
|
+
process.on("exit", () => {
|
|
23
|
+
for (const sentinelFilePath of ownedSentinelFilePaths) try {
|
|
24
|
+
(0, node_fs.rmSync)(sentinelFilePath, { force: true });
|
|
25
|
+
} catch {}
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Reads the sentinel file, returning `undefined` when it does not exist or
|
|
29
|
+
* cannot be parsed.
|
|
30
|
+
*
|
|
31
|
+
* Sentinels written by older versions carry no `status`; they always describe a
|
|
32
|
+
* finished run, so they are reported as `done`.
|
|
33
|
+
*/
|
|
34
|
+
const readSentinelState = async (sentinelFilePath) => {
|
|
35
|
+
try {
|
|
36
|
+
const [sentinelStats, raw] = await Promise.all([(0, node_fs_promises.stat)(sentinelFilePath), (0, node_fs_promises.readFile)(sentinelFilePath, "utf8")]);
|
|
37
|
+
const parsed = JSON.parse(raw);
|
|
38
|
+
return {
|
|
39
|
+
version: parsed.version ?? "",
|
|
40
|
+
timestamp: parsed.timestamp ?? 0,
|
|
41
|
+
status: parsed.status ?? "done",
|
|
42
|
+
pid: parsed.pid ?? 0,
|
|
43
|
+
mtimeMs: sentinelStats.mtime.getTime()
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Whether the process that wrote the sentinel is still alive. An unknown PID
|
|
51
|
+
* (legacy sentinel) is assumed alive so the staleness timeout stays the only
|
|
52
|
+
* way to reclaim it.
|
|
53
|
+
*/
|
|
54
|
+
const isOwnerProcessAlive = (pid) => {
|
|
55
|
+
if (!pid || pid === process.pid) return true;
|
|
15
56
|
try {
|
|
57
|
+
process.kill(pid, 0);
|
|
58
|
+
return true;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return error.code === "EPERM";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const serializeSentinel = (timestamp, status) => JSON.stringify({
|
|
64
|
+
version: _intlayer_core_package_json.default.version,
|
|
65
|
+
timestamp,
|
|
66
|
+
status,
|
|
67
|
+
pid: process.pid
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Attempts to take ownership of the sentinel.
|
|
71
|
+
*
|
|
72
|
+
* `wx` makes the creation atomic, so exactly one process can win even when
|
|
73
|
+
* several start at the same moment.
|
|
74
|
+
*
|
|
75
|
+
* @returns `true` when this process now owns the sentinel, `false` when another
|
|
76
|
+
* process created it first.
|
|
77
|
+
*/
|
|
78
|
+
const acquireSentinel = async (sentinelFilePath, timestamp) => {
|
|
79
|
+
const data = serializeSentinel(timestamp, "running");
|
|
80
|
+
for (let attempt = 0; attempt < 2; attempt++) try {
|
|
16
81
|
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(sentinelFilePath), { recursive: true });
|
|
17
|
-
await (0, node_fs_promises.writeFile)(sentinelFilePath,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} catch (retryErr) {
|
|
25
|
-
if (retryErr.code === "EEXIST") return;
|
|
26
|
-
}
|
|
27
|
-
throw err;
|
|
82
|
+
await (0, node_fs_promises.writeFile)(sentinelFilePath, data, { flag: "wx" });
|
|
83
|
+
return true;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const code = error.code;
|
|
86
|
+
if (code === "EEXIST") return false;
|
|
87
|
+
if (code === "ENOENT" && attempt === 0) continue;
|
|
88
|
+
throw error;
|
|
28
89
|
}
|
|
90
|
+
return false;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Rewrites the sentinel owned by this process, overwriting any existing file.
|
|
94
|
+
*/
|
|
95
|
+
const writeOwnedSentinel = async (sentinelFilePath, timestamp, status) => {
|
|
96
|
+
try {
|
|
97
|
+
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(sentinelFilePath), { recursive: true });
|
|
98
|
+
await (0, node_fs_promises.writeFile)(sentinelFilePath, serializeSentinel(timestamp, status));
|
|
99
|
+
} catch {}
|
|
100
|
+
};
|
|
101
|
+
const removeSentinel = async (sentinelFilePath) => {
|
|
102
|
+
try {
|
|
103
|
+
await (0, node_fs_promises.unlink)(sentinelFilePath);
|
|
104
|
+
} catch {}
|
|
29
105
|
};
|
|
30
106
|
/**
|
|
31
107
|
* Ensures a callback function runs only once within a specified time window across multiple processes.
|
|
32
108
|
* Uses a sentinel file to coordinate execution and prevent duplicate work.
|
|
33
109
|
*
|
|
110
|
+
* Processes that lose the race for the sentinel wait for the owner to finish
|
|
111
|
+
* rather than running a competing copy of the callback — concurrent runs would
|
|
112
|
+
* otherwise write to (and clean) the same output directory at the same time.
|
|
113
|
+
*
|
|
34
114
|
* @param sentinelFilePath - Path to the sentinel file used for coordination
|
|
35
115
|
* @param callback - The function to execute (should be async)
|
|
36
116
|
* @param options - The options for the runOnce function
|
|
37
117
|
*
|
|
38
118
|
* @example
|
|
39
119
|
* ```typescript
|
|
40
|
-
* await
|
|
120
|
+
* await runOnce(
|
|
41
121
|
* '/tmp/intlayer-sentinel',
|
|
42
|
-
* async () => {
|
|
43
|
-
* //
|
|
122
|
+
* async ({ renewLock }) => {
|
|
123
|
+
* await cleanOutputDir(configuration); // may delete the sentinel
|
|
124
|
+
* await renewLock();
|
|
44
125
|
* await prepareIntlayer();
|
|
45
126
|
* },
|
|
46
|
-
* 30 * 1000 // 30 seconds cache
|
|
127
|
+
* { cacheTimeoutMs: 30 * 1000 } // 30 seconds cache
|
|
47
128
|
* );
|
|
48
129
|
* ```
|
|
49
130
|
*
|
|
50
131
|
* @throws {Error} When there are unexpected filesystem errors
|
|
51
132
|
*/
|
|
52
133
|
const runOnce = async (sentinelFilePath, callback, options) => {
|
|
53
|
-
const { onIsCached, cacheTimeoutMs, forceRun } = {
|
|
134
|
+
const { onIsCached, cacheTimeoutMs, forceRun, lockWaitTimeoutMs } = {
|
|
54
135
|
...DEFAULT_RUN_ONCE_OPTIONS,
|
|
55
136
|
...options ?? {}
|
|
56
137
|
};
|
|
57
138
|
const currentTimestamp = Date.now();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
139
|
+
const waitDeadline = currentTimestamp + lockWaitTimeoutMs;
|
|
140
|
+
while (true) {
|
|
141
|
+
const sentinelState = await readSentinelState(sentinelFilePath);
|
|
142
|
+
if (sentinelState) {
|
|
143
|
+
const sentinelAge = Date.now() - sentinelState.mtimeMs;
|
|
144
|
+
if (sentinelState.status === "running") {
|
|
145
|
+
if (!(sentinelAge > lockWaitTimeoutMs || !isOwnerProcessAlive(sentinelState.pid)) && Date.now() < waitDeadline) {
|
|
146
|
+
await delay(LOCK_POLL_INTERVAL_MS);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
await removeSentinel(sentinelFilePath);
|
|
150
|
+
continue;
|
|
68
151
|
}
|
|
69
|
-
if (!
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
await (0, node_fs_promises.unlink)(sentinelFilePath);
|
|
75
|
-
} catch {}
|
|
76
|
-
else {
|
|
77
|
-
await onIsCached?.();
|
|
78
|
-
return;
|
|
152
|
+
if (!forceRun && sentinelAge <= cacheTimeoutMs && sentinelState.version === _intlayer_core_package_json.default.version) {
|
|
153
|
+
await onIsCached?.();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
await removeSentinel(sentinelFilePath);
|
|
79
157
|
}
|
|
80
|
-
|
|
81
|
-
|
|
158
|
+
if (await acquireSentinel(sentinelFilePath, currentTimestamp)) break;
|
|
159
|
+
await delay(LOCK_POLL_INTERVAL_MS);
|
|
82
160
|
}
|
|
83
|
-
|
|
161
|
+
ownedSentinelFilePaths.add(sentinelFilePath);
|
|
162
|
+
const renewLock = () => writeOwnedSentinel(sentinelFilePath, currentTimestamp, "running");
|
|
84
163
|
try {
|
|
85
|
-
await callback();
|
|
86
|
-
await
|
|
164
|
+
await callback({ renewLock });
|
|
165
|
+
await writeOwnedSentinel(sentinelFilePath, currentTimestamp, "done");
|
|
87
166
|
} catch {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
167
|
+
await removeSentinel(sentinelFilePath);
|
|
168
|
+
} finally {
|
|
169
|
+
ownedSentinelFilePaths.delete(sentinelFilePath);
|
|
91
170
|
}
|
|
92
171
|
};
|
|
93
172
|
|