@intlayer/chokidar 7.1.1-canary.1 → 7.1.2-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
- package/dist/cjs/prepareIntlayer.cjs +1 -1
- package/dist/cjs/prepareIntlayer.cjs.map +1 -1
- package/dist/cjs/utils/runOnce.cjs +18 -10
- package/dist/cjs/utils/runOnce.cjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +1 -1
- package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
- package/dist/esm/prepareIntlayer.mjs +1 -1
- package/dist/esm/prepareIntlayer.mjs.map +1 -1
- package/dist/esm/utils/runOnce.mjs +18 -10
- package/dist/esm/utils/runOnce.mjs.map +1 -1
- package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts +2 -2
- package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts +3 -3
- package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts +3 -3
- package/dist/types/buildIntlayerDictionary/writeMergedDictionary.d.ts +2 -2
- package/dist/types/buildIntlayerDictionary/writeRemoteDictionary.d.ts +2 -2
- package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts +2 -2
- package/dist/types/utils/runOnce.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -16,7 +16,7 @@ const generateDictionaryEntryPoint = (localizedDictionariesPathsRecord, format =
|
|
|
16
16
|
let content = "";
|
|
17
17
|
const formattedDictionaryMap = Object.entries(localizedDictionariesPathsRecord).filter((entry) => Boolean(entry[1])).sort(([a], [b]) => String(a).localeCompare(String(b))).map(([locale, dictionary]) => {
|
|
18
18
|
const relativePath = (0, __intlayer_config.normalizePath)((0, node_path.relative)(dynamicDictionariesDir, dictionary.dictionaryPath));
|
|
19
|
-
if (format === "esm") return ` '${locale}': () => import('./${relativePath}', {
|
|
19
|
+
if (format === "esm") return ` '${locale}': () => import('./${relativePath}', { with: { type: 'json' }}).then(mod => mod.default)`;
|
|
20
20
|
return ` '${locale}': () => Promise.resolve(require('./${relativePath}'))`;
|
|
21
21
|
}).join(",\n");
|
|
22
22
|
content += `const content = {\n${formattedDictionaryMap}\n};\n`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeDynamicDictionary.cjs","names":["formattedDictionaryMap: string","resultDictionariesPaths: LocalizedDictionaryOutput","parallelize","localizedDictionariesPathsRecord: LocalizedDictionaryResult","writeJsonIfChanged","writeFileIfChanged"],"sources":["../../../src/buildIntlayerDictionary/writeDynamicDictionary.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport {\n colorizePath,\n getConfiguration,\n normalizePath,\n} from '@intlayer/config';\nimport { getPerLocaleDictionary } from '@intlayer/core';\nimport type { Dictionary, Locale } from '@intlayer/types';\nimport { parallelize } from '../utils/parallelize';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { writeJsonIfChanged } from '../writeJsonIfChanged';\nimport type { MergedDictionaryOutput } from './writeMergedDictionary';\n\nexport type DictionaryResult = {\n dictionaryPath: string;\n dictionary: Dictionary;\n};\n\nexport type LocalizedDictionaryResult = Partial<\n Record<Locale, DictionaryResult>\n>;\n\nexport type LocalizedDictionaryOutput = Record<\n string,\n LocalizedDictionaryResult\n>;\n\n/**\n * This function generates the content of the dictionary list file\n */\nexport const generateDictionaryEntryPoint = (\n localizedDictionariesPathsRecord: LocalizedDictionaryResult,\n format: 'cjs' | 'esm' = 'esm',\n configuration = getConfiguration()\n): string => {\n const { dynamicDictionariesDir } = configuration.content;\n\n let content = '';\n\n // Format Dictionary Map - map locales to functions\n const formattedDictionaryMap: string = Object.entries(\n localizedDictionariesPathsRecord\n )\n // The following filter/sort preserve determinism of the generated map\n // when files are built in parallel or across different Node versions.\n .filter((entry): entry is [string, DictionaryResult] => Boolean(entry[1]))\n .sort(([a], [b]) => String(a).localeCompare(String(b)))\n .map(([locale, dictionary]) => {\n const relativePath = normalizePath(\n relative(dynamicDictionariesDir, dictionary.dictionaryPath)\n );\n\n if (format === 'esm') {\n return ` '${locale}': () => import('./${relativePath}', {
|
|
1
|
+
{"version":3,"file":"writeDynamicDictionary.cjs","names":["formattedDictionaryMap: string","resultDictionariesPaths: LocalizedDictionaryOutput","parallelize","localizedDictionariesPathsRecord: LocalizedDictionaryResult","writeJsonIfChanged","writeFileIfChanged"],"sources":["../../../src/buildIntlayerDictionary/writeDynamicDictionary.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport {\n colorizePath,\n getConfiguration,\n normalizePath,\n} from '@intlayer/config';\nimport { getPerLocaleDictionary } from '@intlayer/core';\nimport type { Dictionary, Locale } from '@intlayer/types';\nimport { parallelize } from '../utils/parallelize';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { writeJsonIfChanged } from '../writeJsonIfChanged';\nimport type { MergedDictionaryOutput } from './writeMergedDictionary';\n\nexport type DictionaryResult = {\n dictionaryPath: string;\n dictionary: Dictionary;\n};\n\nexport type LocalizedDictionaryResult = Partial<\n Record<Locale, DictionaryResult>\n>;\n\nexport type LocalizedDictionaryOutput = Record<\n string,\n LocalizedDictionaryResult\n>;\n\n/**\n * This function generates the content of the dictionary list file\n */\nexport const generateDictionaryEntryPoint = (\n localizedDictionariesPathsRecord: LocalizedDictionaryResult,\n format: 'cjs' | 'esm' = 'esm',\n configuration = getConfiguration()\n): string => {\n const { dynamicDictionariesDir } = configuration.content;\n\n let content = '';\n\n // Format Dictionary Map - map locales to functions\n const formattedDictionaryMap: string = Object.entries(\n localizedDictionariesPathsRecord\n )\n // The following filter/sort preserve determinism of the generated map\n // when files are built in parallel or across different Node versions.\n .filter((entry): entry is [string, DictionaryResult] => Boolean(entry[1]))\n .sort(([a], [b]) => String(a).localeCompare(String(b)))\n .map(([locale, dictionary]) => {\n const relativePath = normalizePath(\n relative(dynamicDictionariesDir, dictionary.dictionaryPath)\n );\n\n if (format === 'esm') {\n return ` '${locale}': () => import('./${relativePath}', { with: { type: 'json' }}).then(mod => mod.default)`;\n }\n\n return ` '${locale}': () => Promise.resolve(require('./${relativePath}'))`;\n })\n .join(',\\n');\n\n content += `const content = {\\n${formattedDictionaryMap}\\n};\\n`;\n\n if (format === 'esm') content += `export default content;\\n`;\n if (format === 'cjs') content += `module.exports = content;\\n`;\n\n return content;\n};\n\n/**\n * Write the localized dictionaries to the dictionariesDir\n * @param mergedDictionaries - The merged dictionaries\n * @param configuration - The configuration\n * @returns The final dictionaries\n *\n * @example\n * ```ts\n * const unmergedDictionaries = await writeUnmergedDictionaries(dictionaries);\n * const finalDictionaries = await writeFinalDictionaries(unmergedDictionaries);\n * console.log(finalDictionaries);\n *\n * // .intlayer/dynamic_dictionaries/home.json\n * // { key: 'home', content: { ... } },\n * ```\n */\nexport const writeDynamicDictionary = async (\n mergedDictionaries: MergedDictionaryOutput,\n configuration = getConfiguration(),\n formats: ('cjs' | 'esm')[] = ['cjs', 'esm']\n): Promise<LocalizedDictionaryOutput> => {\n const { locales, defaultLocale } = configuration.internationalization;\n const { dynamicDictionariesDir } = configuration.content;\n\n // Create the dictionaries folder if it doesn't exist\n await mkdir(resolve(dynamicDictionariesDir), { recursive: true });\n\n const resultDictionariesPaths: LocalizedDictionaryOutput = {};\n\n // Merge dictionaries with the same key and write to dictionariesDir\n await parallelize(\n Object.entries(mergedDictionaries).sort(([a], [b]) =>\n String(a).localeCompare(String(b))\n ),\n async ([key, dictionaryEntry]) => {\n if (key === 'undefined') return;\n\n const localizedDictionariesPathsRecord: LocalizedDictionaryResult = {};\n\n await parallelize(locales, async (locale) => {\n const localizedDictionary = getPerLocaleDictionary(\n dictionaryEntry.dictionary,\n locale,\n defaultLocale\n );\n\n const outputFileName = `${key}.${locale}.json`;\n const resultFilePath = resolve(dynamicDictionariesDir, outputFileName);\n\n // Write the localized dictionary\n await writeJsonIfChanged(resultFilePath, localizedDictionary).catch(\n (err) => {\n console.error(`Error creating localized ${outputFileName}:`, err);\n }\n );\n\n localizedDictionariesPathsRecord[locale] = {\n dictionaryPath: resultFilePath,\n dictionary: localizedDictionary,\n };\n });\n\n resultDictionariesPaths[key] = localizedDictionariesPathsRecord;\n\n await parallelize(formats, async (format) => {\n const extension = format === 'cjs' ? 'cjs' : 'mjs';\n const content = generateDictionaryEntryPoint(\n localizedDictionariesPathsRecord,\n format,\n configuration\n );\n\n await writeFileIfChanged(\n resolve(dynamicDictionariesDir, `${key}.${extension}`),\n content\n ).catch((err) => {\n console.error(\n `Error creating dynamic ${colorizePath(resolve(dynamicDictionariesDir, `${key}.${extension}`))}:`,\n err\n );\n });\n });\n }\n );\n\n return resultDictionariesPaths;\n};\n"],"mappings":";;;;;;;;;;;;;AA+BA,MAAa,gCACX,kCACA,SAAwB,OACxB,yDAAkC,KACvB;CACX,MAAM,EAAE,2BAA2B,cAAc;CAEjD,IAAI,UAAU;CAGd,MAAMA,yBAAiC,OAAO,QAC5C,iCACD,CAGE,QAAQ,UAA+C,QAAQ,MAAM,GAAG,CAAC,CACzE,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,EAAE,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC,CACtD,KAAK,CAAC,QAAQ,gBAAgB;EAC7B,MAAM,4EACK,wBAAwB,WAAW,eAAe,CAC5D;AAED,MAAI,WAAW,MACb,QAAO,MAAM,OAAO,qBAAqB,aAAa;AAGxD,SAAO,MAAM,OAAO,sCAAsC,aAAa;GACvE,CACD,KAAK,MAAM;AAEd,YAAW,sBAAsB,uBAAuB;AAExD,KAAI,WAAW,MAAO,YAAW;AACjC,KAAI,WAAW,MAAO,YAAW;AAEjC,QAAO;;;;;;;;;;;;;;;;;;AAmBT,MAAa,yBAAyB,OACpC,oBACA,yDAAkC,EAClC,UAA6B,CAAC,OAAO,MAAM,KACJ;CACvC,MAAM,EAAE,SAAS,kBAAkB,cAAc;CACjD,MAAM,EAAE,2BAA2B,cAAc;AAGjD,0DAAoB,uBAAuB,EAAE,EAAE,WAAW,MAAM,CAAC;CAEjE,MAAMC,0BAAqD,EAAE;AAG7D,OAAMC,sCACJ,OAAO,QAAQ,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,OAC7C,OAAO,EAAE,CAAC,cAAc,OAAO,EAAE,CAAC,CACnC,EACD,OAAO,CAAC,KAAK,qBAAqB;AAChC,MAAI,QAAQ,YAAa;EAEzB,MAAMC,mCAA8D,EAAE;AAEtE,QAAMD,sCAAY,SAAS,OAAO,WAAW;GAC3C,MAAM,kEACJ,gBAAgB,YAChB,QACA,cACD;GAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,OAAO;GACxC,MAAM,wCAAyB,wBAAwB,eAAe;AAGtE,SAAME,8CAAmB,gBAAgB,oBAAoB,CAAC,OAC3D,QAAQ;AACP,YAAQ,MAAM,4BAA4B,eAAe,IAAI,IAAI;KAEpE;AAED,oCAAiC,UAAU;IACzC,gBAAgB;IAChB,YAAY;IACb;IACD;AAEF,0BAAwB,OAAO;AAE/B,QAAMF,sCAAY,SAAS,OAAO,WAAW;GAC3C,MAAM,YAAY,WAAW,QAAQ,QAAQ;GAC7C,MAAM,UAAU,6BACd,kCACA,QACA,cACD;AAED,SAAMG,qEACI,wBAAwB,GAAG,IAAI,GAAG,YAAY,EACtD,QACD,CAAC,OAAO,QAAQ;AACf,YAAQ,MACN,qFAA+C,wBAAwB,GAAG,IAAI,GAAG,YAAY,CAAC,CAAC,IAC/F,IACD;KACD;IACF;GAEL;AAED,QAAO"}
|
|
@@ -21,7 +21,7 @@ const DEFAULT_PREPARE_INTLAYER_OPTIONS = {
|
|
|
21
21
|
cacheTimeoutMs: 1e3 * 60 * 60
|
|
22
22
|
};
|
|
23
23
|
const prepareIntlayer = async (configuration, options) => {
|
|
24
|
-
(0, __intlayer_config.checkVersionsConsistency)(configuration);
|
|
24
|
+
await (0, __intlayer_config.checkVersionsConsistency)(configuration);
|
|
25
25
|
const appLogger = (0, __intlayer_config.getAppLogger)(configuration);
|
|
26
26
|
const sentinelPath = (0, node_path.join)(configuration.content.cacheDir, "intlayer-prepared.lock");
|
|
27
27
|
const versionCache = (0, __intlayer_config.cacheDisk)(configuration, ["intlayer-version"]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","listDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { join } from 'node:path';\nimport {\n ANSIColors,\n cacheDisk,\n checkVersionsConsistency,\n colorize,\n getAppLogger,\n} from '@intlayer/config';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport type { IntlayerConfig } from '@intlayer/types';\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 { listDictionaries } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport { writeConfiguration } from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\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 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 checkVersionsConsistency(configuration);\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.content.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 { clean, format, forceRun, onIsCached, cacheTimeoutMs } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun: !isCorrectVersion,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\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 files: string[] = await listDictionaries(configuration);\n\n const dictionaries = await loadDictionaries(files, configuration);\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 format,\n false\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 dictionariesPaths = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionaryPath);\n\n await createTypes(dictionariesPaths, configuration);\n\n await createDictionaryEntryPoint(configuration);\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 await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\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":";;;;;;;;;;;;;;;;;AA4BA,MAAM,mCAAmC;CACvC,OAAO;CACP,QAAQ,CAAC,OAAO,MAAM;CACtB,gBAAgB,MAAO,KAAK;CAC7B;AAED,MAAa,kBAAkB,OAC7B,eACA,YACG;AACH,
|
|
1
|
+
{"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","listDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { join } from 'node:path';\nimport {\n ANSIColors,\n cacheDisk,\n checkVersionsConsistency,\n colorize,\n getAppLogger,\n} from '@intlayer/config';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport type { IntlayerConfig } from '@intlayer/types';\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 { listDictionaries } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport { writeConfiguration } from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\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 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 await checkVersionsConsistency(configuration);\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.content.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 { clean, format, forceRun, onIsCached, cacheTimeoutMs } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun: !isCorrectVersion,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\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 files: string[] = await listDictionaries(configuration);\n\n const dictionaries = await loadDictionaries(files, configuration);\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 format,\n false\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 dictionariesPaths = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionaryPath);\n\n await createTypes(dictionariesPaths, configuration);\n\n await createDictionaryEntryPoint(configuration);\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 await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\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":";;;;;;;;;;;;;;;;;AA4BA,MAAM,mCAAmC;CACvC,OAAO;CACP,QAAQ,CAAC,OAAO,MAAM;CACtB,gBAAgB,MAAO,KAAK;CAC7B;AAED,MAAa,kBAAkB,OAC7B,eACA,YACG;AACH,uDAA+B,cAAc;CAC7C,MAAM,gDAAyB,cAAc;CAE7C,MAAM,mCACJ,cAAc,QAAQ,UACtB,yBACD;CAED,MAAM,gDAAyB,eAAe,CAAC,mBAAmB,CAAC;CACnE,MAAM,uBAAuB,MAAM,aAAa,KAAK;CACrD,MAAM,mBAAmB,QACvB,wBAAwB,yBAAyBA,uCAAY,QAC9D;CAED,MAAM,EAAE,OAAO,QAAQ,UAAU,YAAY,mBAAmB;EAC9D,GAAG;EACH,UAAU,CAAC;EACX,GAAI,WAAW,EAAE;EAClB;AAGD,OAAMC,8BACJ,cACA,YAAY;AACV,MAAI,SAAS,CAAC,iBACZ,OAAMC,sCAAe,cAAc;AAGrC,QAAM,aAAa,IAAIF,uCAAY,QAAQ;EAE3C,MAAM,qBAAqB,KAAK,KAAK;AAErC,YAAU,CACR,sDACS,KAAKA,uCAAY,QAAQ,IAAIG,6BAAW,UAAU,CAC5D,CAAC;AAEF,QAAMC,oDAAmB,cAAc;EAEvC,MAAM,2BAA2B,KAAK,KAAK;AAE3C,YACE,CACE,yDAEE,IAAI,2BAA2B,mBAAmB,MAClDD,6BAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;EAID,MAAM,eAAe,MAAME,2DAFH,MAAMC,8CAAiB,cAAc,EAEV,cAAc;EAEjE,MAAM,yBAAyB,KAAK,KAAK;AAEzC,YACE,CACE,kDAEE,CACE,aAAa,mBAAmB,SAC9B,aAAa,mBAAmB,SAClC,IACI;GACE,WAAW,yBAAyB,yBAAyB;GAC7D,aAAa,kBAAkB,SAAS,IACpC,YAAY,aAAa,KAAK,kBAAkB,MAChD;GACJ,aAAa,mBAAmB,SAAS,IACrC,aAAa,aAAa,KAAK,mBAAmB,MAClD;GACJ,aAAa,mBAAmB,SAAS,IACrC,aAAa,aAAa,KAAK,mBAAmB,MAClD;GACJ;GACD,CAAC,KAAK,GAAG,GACV,IAAI,yBAAyB,yBAAyB,KAC3D,CAAC,KAAK,GAAG,EACVH,6BAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;EAGD,MAAM,qBAAqB,MAAMI,wEAC/B;GACE,GAAG,aAAa;GAChB,GAAG,aAAa;GAChB,GAAG,aAAa;GACjB,EACD,eACA,QACA,MACD;AAID,QAAMC,4EACJ,aAAa,oBACb,cACD;AAMD,QAAMC,0CAJoB,OAAO,OAC/B,oBAAoB,sBAAsB,EAAE,CAC7C,CAAC,KAAK,eAAe,WAAW,eAAe,EAEX,cAAc;AAEnD,QAAMC,yFAA2B,cAAc;EAE/C,MAAM,wBAAwB,KAAK,KAAK;AAExC,YAAU,CACR,sDAEE,IAAI,wBAAwB,mBAAmB,MAC/CP,6BAAW,UACZ,CACF,CAAC;AAEF,QAAMQ,qEAAyB,cAAc;AAI7C,YACE,CACE,6DAEE,IAN8B,KAAK,KAAK,GAMN,sBAAsB,MACxDR,6BAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;AAID,aAAW,MAAM,UAAU,cAAc,WAAW,EAAE,EAAE;GACtD,MAAM,EAAE,sBAAsB,uBAAuB;AAErD,SAAM,OAAO,aAAa;IACxB,cAAc;KACZ;KACA;KACD;IACD;IACD,CAAC;;AAIJ,YACE,CAAC,wCAAiB,GAFS,KAAK,KAAK,GAAG,mBAEE,KAAKA,6BAAW,MAAM,CAAC,EACjE;GACE,OAAO;GACP,WAAW;GACZ,CACF;IAEH;EACE;EACA;EACA;EACD,CACF"}
|
|
@@ -6,6 +6,19 @@ __intlayer_core_package_json = require_rolldown_runtime.__toESM(__intlayer_core_
|
|
|
6
6
|
|
|
7
7
|
//#region src/utils/runOnce.ts
|
|
8
8
|
const DEFAULT_RUN_ONCE_OPTIONS = { cacheTimeoutMs: 60 * 1e3 };
|
|
9
|
+
const writeSentinelFile = async (sentinelFilePath, currentTimestamp) => {
|
|
10
|
+
try {
|
|
11
|
+
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(sentinelFilePath), { recursive: true });
|
|
12
|
+
const data = {
|
|
13
|
+
version: __intlayer_core_package_json.default.version,
|
|
14
|
+
timestamp: currentTimestamp
|
|
15
|
+
};
|
|
16
|
+
await (0, node_fs_promises.writeFile)(sentinelFilePath, JSON.stringify(data), { flag: "wx" });
|
|
17
|
+
} catch (err) {
|
|
18
|
+
if (err.code === "EEXIST") return;
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
9
22
|
/**
|
|
10
23
|
* Ensures a callback function runs only once within a specified time window across multiple processes.
|
|
11
24
|
* Uses a sentinel file to coordinate execution and prevent duplicate work.
|
|
@@ -61,18 +74,13 @@ const runOnce = async (sentinelFilePath, callback, options) => {
|
|
|
61
74
|
} catch (err) {
|
|
62
75
|
if (err.code === "ENOENT") {} else throw err;
|
|
63
76
|
}
|
|
77
|
+
writeSentinelFile(sentinelFilePath, currentTimestamp);
|
|
64
78
|
try {
|
|
65
|
-
await (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
70
|
-
await (0, node_fs_promises.writeFile)(sentinelFilePath, JSON.stringify(data), { flag: "wx" });
|
|
71
|
-
} catch (err) {
|
|
72
|
-
if (err.code === "EEXIST") return;
|
|
73
|
-
throw err;
|
|
79
|
+
await callback();
|
|
80
|
+
writeSentinelFile(sentinelFilePath, currentTimestamp);
|
|
81
|
+
} catch {
|
|
82
|
+
await (0, node_fs_promises.unlink)(sentinelFilePath);
|
|
74
83
|
}
|
|
75
|
-
await callback();
|
|
76
84
|
};
|
|
77
85
|
|
|
78
86
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runOnce.cjs","names":["
|
|
1
|
+
{"version":3,"file":"runOnce.cjs","names":["data: SentinelData","packageJson","err: any","cachedVersion: string | undefined"],"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":["import { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport packageJson from '@intlayer/core/package.json' with { type: 'json' };\n\ntype RunOnceOptions = {\n /**\n * The function to execute when the sentinel is not found or is older than the cache timeout.\n */\n onIsCached?: () => void | Promise<void>;\n /**\n * The time window in milliseconds during which the sentinel is considered valid.\n *\n * @default 60000 = 1 minute\n */\n cacheTimeoutMs?: number;\n /**\n * If true, the callback will always run. If undefined, the callback will run only if the sentinel is older than the cache timeout.\n *\n * @default false\n */\n forceRun?: boolean;\n};\n\nconst DEFAULT_RUN_ONCE_OPTIONS = {\n cacheTimeoutMs: 60 * 1000, // 1 minute in milliseconds,\n} satisfies RunOnceOptions;\n\ntype SentinelData = {\n version: string;\n timestamp: number;\n};\n\nconst writeSentinelFile = async (\n sentinelFilePath: string,\n currentTimestamp: number\n) => {\n try {\n // Ensure the directory exists before writing the file\n await mkdir(dirname(sentinelFilePath), { recursive: true });\n\n // O_EXCL ensures only the *first* process can create the file\n const data: SentinelData = {\n version: packageJson.version,\n timestamp: currentTimestamp,\n };\n await writeFile(sentinelFilePath, JSON.stringify(data), { flag: 'wx' });\n } catch (err: any) {\n if (err.code === 'EEXIST') {\n // Another process already created it → we're done\n return;\n }\n throw err; // unexpected FS error\n }\n};\n\n/**\n * Ensures a callback function runs only once within a specified time window across multiple processes.\n * Uses a sentinel file to coordinate execution and prevent duplicate work.\n *\n * @param sentinelFilePath - Path to the sentinel file used for coordination\n * @param callback - The function to execute (should be async)\n * @param options - The options for the runOnce function\n *\n * @example\n * ```typescript\n * await runPrepareIntlayerOnce(\n * '/tmp/intlayer-sentinel',\n * async () => {\n * // Your initialization logic here\n * await prepareIntlayer();\n * },\n * 30 * 1000 // 30 seconds cache\n * );\n * ```\n *\n * @throws {Error} When there are unexpected filesystem errors\n */\nexport const runOnce = async (\n sentinelFilePath: string,\n callback: () => void | Promise<void>,\n options?: RunOnceOptions\n) => {\n const { onIsCached, cacheTimeoutMs, forceRun } = {\n ...DEFAULT_RUN_ONCE_OPTIONS,\n ...(options ?? {}),\n };\n const currentTimestamp = Date.now();\n\n try {\n // Check if sentinel file exists and get its stats\n const sentinelStats = await stat(sentinelFilePath);\n const sentinelAge = currentTimestamp - sentinelStats.mtime.getTime();\n\n // Determine if we should rebuild based on cache age, force flag, or version mismatch\n let shouldRebuild = Boolean(forceRun) || sentinelAge > cacheTimeoutMs!;\n\n if (!shouldRebuild) {\n try {\n const raw = await readFile(sentinelFilePath, 'utf8');\n let cachedVersion: string | undefined;\n try {\n const parsed = JSON.parse(raw) as Partial<SentinelData>;\n cachedVersion = parsed.version;\n } catch {\n // Legacy format (timestamp only). Force a rebuild once to write versioned sentinel.\n cachedVersion = undefined;\n }\n\n if (!cachedVersion || cachedVersion !== packageJson.version) {\n shouldRebuild = true;\n }\n } catch {\n // If we cannot read the file, err on the safe side and rebuild\n shouldRebuild = true;\n }\n }\n\n if (shouldRebuild) {\n try {\n await unlink(sentinelFilePath);\n } catch (err: any) {\n if (err.code !== 'ENOENT') throw err;\n }\n // Fall through to create new sentinel and rebuild\n } else {\n await onIsCached?.();\n // Sentinel is recent and versions match, no need to rebuild\n return;\n }\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n // File doesn't exist, continue to create it\n } else {\n throw err; // unexpected FS error\n }\n }\n\n // Write sentinel file before to block parallel processes\n writeSentinelFile(sentinelFilePath, currentTimestamp);\n\n try {\n await callback();\n\n // Write sentinel file after to ensure the first one has not been removed with cleanOutputDir\n writeSentinelFile(sentinelFilePath, currentTimestamp);\n } catch {\n await unlink(sentinelFilePath); // Remove sentinel file if an error occurs\n }\n};\n"],"mappings":";;;;;;;AAuBA,MAAM,2BAA2B,EAC/B,gBAAgB,KAAK,KACtB;AAOD,MAAM,oBAAoB,OACxB,kBACA,qBACG;AACH,KAAI;AAEF,2DAAoB,iBAAiB,EAAE,EAAE,WAAW,MAAM,CAAC;EAG3D,MAAMA,OAAqB;GACzB,SAASC,qCAAY;GACrB,WAAW;GACZ;AACD,wCAAgB,kBAAkB,KAAK,UAAU,KAAK,EAAE,EAAE,MAAM,MAAM,CAAC;UAChEC,KAAU;AACjB,MAAI,IAAI,SAAS,SAEf;AAEF,QAAM;;;;;;;;;;;;;;;;;;;;;;;;;AA0BV,MAAa,UAAU,OACrB,kBACA,UACA,YACG;CACH,MAAM,EAAE,YAAY,gBAAgB,aAAa;EAC/C,GAAG;EACH,GAAI,WAAW,EAAE;EAClB;CACD,MAAM,mBAAmB,KAAK,KAAK;AAEnC,KAAI;EAGF,MAAM,cAAc,oBADE,iCAAW,iBAAiB,EACG,MAAM,SAAS;EAGpE,IAAI,gBAAgB,QAAQ,SAAS,IAAI,cAAc;AAEvD,MAAI,CAAC,cACH,KAAI;GACF,MAAM,MAAM,qCAAe,kBAAkB,OAAO;GACpD,IAAIC;AACJ,OAAI;AAEF,oBADe,KAAK,MAAM,IAAI,CACP;WACjB;AAEN,oBAAgB;;AAGlB,OAAI,CAAC,iBAAiB,kBAAkBF,qCAAY,QAClD,iBAAgB;UAEZ;AAEN,mBAAgB;;AAIpB,MAAI,cACF,KAAI;AACF,sCAAa,iBAAiB;WACvBC,KAAU;AACjB,OAAI,IAAI,SAAS,SAAU,OAAM;;OAG9B;AACL,SAAM,cAAc;AAEpB;;UAEKA,KAAU;AACjB,MAAI,IAAI,SAAS,UAAU,OAGzB,OAAM;;AAKV,mBAAkB,kBAAkB,iBAAiB;AAErD,KAAI;AACF,QAAM,UAAU;AAGhB,oBAAkB,kBAAkB,iBAAiB;SAC/C;AACN,qCAAa,iBAAiB"}
|
|
@@ -15,7 +15,7 @@ const generateDictionaryEntryPoint = (localizedDictionariesPathsRecord, format =
|
|
|
15
15
|
let content = "";
|
|
16
16
|
const formattedDictionaryMap = Object.entries(localizedDictionariesPathsRecord).filter((entry) => Boolean(entry[1])).sort(([a], [b]) => String(a).localeCompare(String(b))).map(([locale, dictionary]) => {
|
|
17
17
|
const relativePath = normalizePath(relative(dynamicDictionariesDir, dictionary.dictionaryPath));
|
|
18
|
-
if (format === "esm") return ` '${locale}': () => import('./${relativePath}', {
|
|
18
|
+
if (format === "esm") return ` '${locale}': () => import('./${relativePath}', { with: { type: 'json' }}).then(mod => mod.default)`;
|
|
19
19
|
return ` '${locale}': () => Promise.resolve(require('./${relativePath}'))`;
|
|
20
20
|
}).join(",\n");
|
|
21
21
|
content += `const content = {\n${formattedDictionaryMap}\n};\n`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeDynamicDictionary.mjs","names":["formattedDictionaryMap: string","resultDictionariesPaths: LocalizedDictionaryOutput","localizedDictionariesPathsRecord: LocalizedDictionaryResult"],"sources":["../../../src/buildIntlayerDictionary/writeDynamicDictionary.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport {\n colorizePath,\n getConfiguration,\n normalizePath,\n} from '@intlayer/config';\nimport { getPerLocaleDictionary } from '@intlayer/core';\nimport type { Dictionary, Locale } from '@intlayer/types';\nimport { parallelize } from '../utils/parallelize';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { writeJsonIfChanged } from '../writeJsonIfChanged';\nimport type { MergedDictionaryOutput } from './writeMergedDictionary';\n\nexport type DictionaryResult = {\n dictionaryPath: string;\n dictionary: Dictionary;\n};\n\nexport type LocalizedDictionaryResult = Partial<\n Record<Locale, DictionaryResult>\n>;\n\nexport type LocalizedDictionaryOutput = Record<\n string,\n LocalizedDictionaryResult\n>;\n\n/**\n * This function generates the content of the dictionary list file\n */\nexport const generateDictionaryEntryPoint = (\n localizedDictionariesPathsRecord: LocalizedDictionaryResult,\n format: 'cjs' | 'esm' = 'esm',\n configuration = getConfiguration()\n): string => {\n const { dynamicDictionariesDir } = configuration.content;\n\n let content = '';\n\n // Format Dictionary Map - map locales to functions\n const formattedDictionaryMap: string = Object.entries(\n localizedDictionariesPathsRecord\n )\n // The following filter/sort preserve determinism of the generated map\n // when files are built in parallel or across different Node versions.\n .filter((entry): entry is [string, DictionaryResult] => Boolean(entry[1]))\n .sort(([a], [b]) => String(a).localeCompare(String(b)))\n .map(([locale, dictionary]) => {\n const relativePath = normalizePath(\n relative(dynamicDictionariesDir, dictionary.dictionaryPath)\n );\n\n if (format === 'esm') {\n return ` '${locale}': () => import('./${relativePath}', {
|
|
1
|
+
{"version":3,"file":"writeDynamicDictionary.mjs","names":["formattedDictionaryMap: string","resultDictionariesPaths: LocalizedDictionaryOutput","localizedDictionariesPathsRecord: LocalizedDictionaryResult"],"sources":["../../../src/buildIntlayerDictionary/writeDynamicDictionary.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport {\n colorizePath,\n getConfiguration,\n normalizePath,\n} from '@intlayer/config';\nimport { getPerLocaleDictionary } from '@intlayer/core';\nimport type { Dictionary, Locale } from '@intlayer/types';\nimport { parallelize } from '../utils/parallelize';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { writeJsonIfChanged } from '../writeJsonIfChanged';\nimport type { MergedDictionaryOutput } from './writeMergedDictionary';\n\nexport type DictionaryResult = {\n dictionaryPath: string;\n dictionary: Dictionary;\n};\n\nexport type LocalizedDictionaryResult = Partial<\n Record<Locale, DictionaryResult>\n>;\n\nexport type LocalizedDictionaryOutput = Record<\n string,\n LocalizedDictionaryResult\n>;\n\n/**\n * This function generates the content of the dictionary list file\n */\nexport const generateDictionaryEntryPoint = (\n localizedDictionariesPathsRecord: LocalizedDictionaryResult,\n format: 'cjs' | 'esm' = 'esm',\n configuration = getConfiguration()\n): string => {\n const { dynamicDictionariesDir } = configuration.content;\n\n let content = '';\n\n // Format Dictionary Map - map locales to functions\n const formattedDictionaryMap: string = Object.entries(\n localizedDictionariesPathsRecord\n )\n // The following filter/sort preserve determinism of the generated map\n // when files are built in parallel or across different Node versions.\n .filter((entry): entry is [string, DictionaryResult] => Boolean(entry[1]))\n .sort(([a], [b]) => String(a).localeCompare(String(b)))\n .map(([locale, dictionary]) => {\n const relativePath = normalizePath(\n relative(dynamicDictionariesDir, dictionary.dictionaryPath)\n );\n\n if (format === 'esm') {\n return ` '${locale}': () => import('./${relativePath}', { with: { type: 'json' }}).then(mod => mod.default)`;\n }\n\n return ` '${locale}': () => Promise.resolve(require('./${relativePath}'))`;\n })\n .join(',\\n');\n\n content += `const content = {\\n${formattedDictionaryMap}\\n};\\n`;\n\n if (format === 'esm') content += `export default content;\\n`;\n if (format === 'cjs') content += `module.exports = content;\\n`;\n\n return content;\n};\n\n/**\n * Write the localized dictionaries to the dictionariesDir\n * @param mergedDictionaries - The merged dictionaries\n * @param configuration - The configuration\n * @returns The final dictionaries\n *\n * @example\n * ```ts\n * const unmergedDictionaries = await writeUnmergedDictionaries(dictionaries);\n * const finalDictionaries = await writeFinalDictionaries(unmergedDictionaries);\n * console.log(finalDictionaries);\n *\n * // .intlayer/dynamic_dictionaries/home.json\n * // { key: 'home', content: { ... } },\n * ```\n */\nexport const writeDynamicDictionary = async (\n mergedDictionaries: MergedDictionaryOutput,\n configuration = getConfiguration(),\n formats: ('cjs' | 'esm')[] = ['cjs', 'esm']\n): Promise<LocalizedDictionaryOutput> => {\n const { locales, defaultLocale } = configuration.internationalization;\n const { dynamicDictionariesDir } = configuration.content;\n\n // Create the dictionaries folder if it doesn't exist\n await mkdir(resolve(dynamicDictionariesDir), { recursive: true });\n\n const resultDictionariesPaths: LocalizedDictionaryOutput = {};\n\n // Merge dictionaries with the same key and write to dictionariesDir\n await parallelize(\n Object.entries(mergedDictionaries).sort(([a], [b]) =>\n String(a).localeCompare(String(b))\n ),\n async ([key, dictionaryEntry]) => {\n if (key === 'undefined') return;\n\n const localizedDictionariesPathsRecord: LocalizedDictionaryResult = {};\n\n await parallelize(locales, async (locale) => {\n const localizedDictionary = getPerLocaleDictionary(\n dictionaryEntry.dictionary,\n locale,\n defaultLocale\n );\n\n const outputFileName = `${key}.${locale}.json`;\n const resultFilePath = resolve(dynamicDictionariesDir, outputFileName);\n\n // Write the localized dictionary\n await writeJsonIfChanged(resultFilePath, localizedDictionary).catch(\n (err) => {\n console.error(`Error creating localized ${outputFileName}:`, err);\n }\n );\n\n localizedDictionariesPathsRecord[locale] = {\n dictionaryPath: resultFilePath,\n dictionary: localizedDictionary,\n };\n });\n\n resultDictionariesPaths[key] = localizedDictionariesPathsRecord;\n\n await parallelize(formats, async (format) => {\n const extension = format === 'cjs' ? 'cjs' : 'mjs';\n const content = generateDictionaryEntryPoint(\n localizedDictionariesPathsRecord,\n format,\n configuration\n );\n\n await writeFileIfChanged(\n resolve(dynamicDictionariesDir, `${key}.${extension}`),\n content\n ).catch((err) => {\n console.error(\n `Error creating dynamic ${colorizePath(resolve(dynamicDictionariesDir, `${key}.${extension}`))}:`,\n err\n );\n });\n });\n }\n );\n\n return resultDictionariesPaths;\n};\n"],"mappings":";;;;;;;;;;;;AA+BA,MAAa,gCACX,kCACA,SAAwB,OACxB,gBAAgB,kBAAkB,KACvB;CACX,MAAM,EAAE,2BAA2B,cAAc;CAEjD,IAAI,UAAU;CAGd,MAAMA,yBAAiC,OAAO,QAC5C,iCACD,CAGE,QAAQ,UAA+C,QAAQ,MAAM,GAAG,CAAC,CACzE,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,EAAE,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC,CACtD,KAAK,CAAC,QAAQ,gBAAgB;EAC7B,MAAM,eAAe,cACnB,SAAS,wBAAwB,WAAW,eAAe,CAC5D;AAED,MAAI,WAAW,MACb,QAAO,MAAM,OAAO,qBAAqB,aAAa;AAGxD,SAAO,MAAM,OAAO,sCAAsC,aAAa;GACvE,CACD,KAAK,MAAM;AAEd,YAAW,sBAAsB,uBAAuB;AAExD,KAAI,WAAW,MAAO,YAAW;AACjC,KAAI,WAAW,MAAO,YAAW;AAEjC,QAAO;;;;;;;;;;;;;;;;;;AAmBT,MAAa,yBAAyB,OACpC,oBACA,gBAAgB,kBAAkB,EAClC,UAA6B,CAAC,OAAO,MAAM,KACJ;CACvC,MAAM,EAAE,SAAS,kBAAkB,cAAc;CACjD,MAAM,EAAE,2BAA2B,cAAc;AAGjD,OAAM,MAAM,QAAQ,uBAAuB,EAAE,EAAE,WAAW,MAAM,CAAC;CAEjE,MAAMC,0BAAqD,EAAE;AAG7D,OAAM,YACJ,OAAO,QAAQ,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,OAC7C,OAAO,EAAE,CAAC,cAAc,OAAO,EAAE,CAAC,CACnC,EACD,OAAO,CAAC,KAAK,qBAAqB;AAChC,MAAI,QAAQ,YAAa;EAEzB,MAAMC,mCAA8D,EAAE;AAEtE,QAAM,YAAY,SAAS,OAAO,WAAW;GAC3C,MAAM,sBAAsB,uBAC1B,gBAAgB,YAChB,QACA,cACD;GAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,OAAO;GACxC,MAAM,iBAAiB,QAAQ,wBAAwB,eAAe;AAGtE,SAAM,mBAAmB,gBAAgB,oBAAoB,CAAC,OAC3D,QAAQ;AACP,YAAQ,MAAM,4BAA4B,eAAe,IAAI,IAAI;KAEpE;AAED,oCAAiC,UAAU;IACzC,gBAAgB;IAChB,YAAY;IACb;IACD;AAEF,0BAAwB,OAAO;AAE/B,QAAM,YAAY,SAAS,OAAO,WAAW;GAC3C,MAAM,YAAY,WAAW,QAAQ,QAAQ;GAC7C,MAAM,UAAU,6BACd,kCACA,QACA,cACD;AAED,SAAM,mBACJ,QAAQ,wBAAwB,GAAG,IAAI,GAAG,YAAY,EACtD,QACD,CAAC,OAAO,QAAQ;AACf,YAAQ,MACN,0BAA0B,aAAa,QAAQ,wBAAwB,GAAG,IAAI,GAAG,YAAY,CAAC,CAAC,IAC/F,IACD;KACD;IACF;GAEL;AAED,QAAO"}
|
|
@@ -19,7 +19,7 @@ const DEFAULT_PREPARE_INTLAYER_OPTIONS = {
|
|
|
19
19
|
cacheTimeoutMs: 1e3 * 60 * 60
|
|
20
20
|
};
|
|
21
21
|
const prepareIntlayer = async (configuration, options) => {
|
|
22
|
-
checkVersionsConsistency(configuration);
|
|
22
|
+
await checkVersionsConsistency(configuration);
|
|
23
23
|
const appLogger = getAppLogger(configuration);
|
|
24
24
|
const sentinelPath = join(configuration.content.cacheDir, "intlayer-prepared.lock");
|
|
25
25
|
const versionCache = cacheDisk(configuration, ["intlayer-version"]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepareIntlayer.mjs","names":[],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { join } from 'node:path';\nimport {\n ANSIColors,\n cacheDisk,\n checkVersionsConsistency,\n colorize,\n getAppLogger,\n} from '@intlayer/config';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport type { IntlayerConfig } from '@intlayer/types';\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 { listDictionaries } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport { writeConfiguration } from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\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 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 checkVersionsConsistency(configuration);\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.content.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 { clean, format, forceRun, onIsCached, cacheTimeoutMs } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun: !isCorrectVersion,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\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 files: string[] = await listDictionaries(configuration);\n\n const dictionaries = await loadDictionaries(files, configuration);\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 format,\n false\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 dictionariesPaths = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionaryPath);\n\n await createTypes(dictionariesPaths, configuration);\n\n await createDictionaryEntryPoint(configuration);\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 await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\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":";;;;;;;;;;;;;;;AA4BA,MAAM,mCAAmC;CACvC,OAAO;CACP,QAAQ,CAAC,OAAO,MAAM;CACtB,gBAAgB,MAAO,KAAK;CAC7B;AAED,MAAa,kBAAkB,OAC7B,eACA,YACG;AACH,
|
|
1
|
+
{"version":3,"file":"prepareIntlayer.mjs","names":[],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { join } from 'node:path';\nimport {\n ANSIColors,\n cacheDisk,\n checkVersionsConsistency,\n colorize,\n getAppLogger,\n} from '@intlayer/config';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport type { IntlayerConfig } from '@intlayer/types';\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 { listDictionaries } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport { writeConfiguration } from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\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 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 await checkVersionsConsistency(configuration);\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.content.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 { clean, format, forceRun, onIsCached, cacheTimeoutMs } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun: !isCorrectVersion,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\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 files: string[] = await listDictionaries(configuration);\n\n const dictionaries = await loadDictionaries(files, configuration);\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 format,\n false\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 dictionariesPaths = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionaryPath);\n\n await createTypes(dictionariesPaths, configuration);\n\n await createDictionaryEntryPoint(configuration);\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 await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\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":";;;;;;;;;;;;;;;AA4BA,MAAM,mCAAmC;CACvC,OAAO;CACP,QAAQ,CAAC,OAAO,MAAM;CACtB,gBAAgB,MAAO,KAAK;CAC7B;AAED,MAAa,kBAAkB,OAC7B,eACA,YACG;AACH,OAAM,yBAAyB,cAAc;CAC7C,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,eAAe,KACnB,cAAc,QAAQ,UACtB,yBACD;CAED,MAAM,eAAe,UAAU,eAAe,CAAC,mBAAmB,CAAC;CACnE,MAAM,uBAAuB,MAAM,aAAa,KAAK;CACrD,MAAM,mBAAmB,QACvB,wBAAwB,yBAAyB,YAAY,QAC9D;CAED,MAAM,EAAE,OAAO,QAAQ,UAAU,YAAY,mBAAmB;EAC9D,GAAG;EACH,UAAU,CAAC;EACX,GAAI,WAAW,EAAE;EAClB;AAGD,OAAM,QACJ,cACA,YAAY;AACV,MAAI,SAAS,CAAC,iBACZ,OAAM,eAAe,cAAc;AAGrC,QAAM,aAAa,IAAI,YAAY,QAAQ;EAE3C,MAAM,qBAAqB,KAAK,KAAK;AAErC,YAAU,CACR,sBACA,SAAS,KAAK,YAAY,QAAQ,IAAI,WAAW,UAAU,CAC5D,CAAC;AAEF,QAAM,mBAAmB,cAAc;EAEvC,MAAM,2BAA2B,KAAK,KAAK;AAE3C,YACE,CACE,yBACA,SACE,IAAI,2BAA2B,mBAAmB,MAClD,WAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;EAID,MAAM,eAAe,MAAM,iBAFH,MAAM,iBAAiB,cAAc,EAEV,cAAc;EAEjE,MAAM,yBAAyB,KAAK,KAAK;AAEzC,YACE,CACE,kBACA,SACE,CACE,aAAa,mBAAmB,SAC9B,aAAa,mBAAmB,SAClC,IACI;GACE,WAAW,yBAAyB,yBAAyB;GAC7D,aAAa,kBAAkB,SAAS,IACpC,YAAY,aAAa,KAAK,kBAAkB,MAChD;GACJ,aAAa,mBAAmB,SAAS,IACrC,aAAa,aAAa,KAAK,mBAAmB,MAClD;GACJ,aAAa,mBAAmB,SAAS,IACrC,aAAa,aAAa,KAAK,mBAAmB,MAClD;GACJ;GACD,CAAC,KAAK,GAAG,GACV,IAAI,yBAAyB,yBAAyB,KAC3D,CAAC,KAAK,GAAG,EACV,WAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;EAGD,MAAM,qBAAqB,MAAM,gBAC/B;GACE,GAAG,aAAa;GAChB,GAAG,aAAa;GAChB,GAAG,aAAa;GACjB,EACD,eACA,QACA,MACD;AAID,QAAM,sBACJ,aAAa,oBACb,cACD;AAMD,QAAM,YAJoB,OAAO,OAC/B,oBAAoB,sBAAsB,EAAE,CAC7C,CAAC,KAAK,eAAe,WAAW,eAAe,EAEX,cAAc;AAEnD,QAAM,2BAA2B,cAAc;EAE/C,MAAM,wBAAwB,KAAK,KAAK;AAExC,YAAU,CACR,sBACA,SACE,IAAI,wBAAwB,mBAAmB,MAC/C,WAAW,UACZ,CACF,CAAC;AAEF,QAAM,yBAAyB,cAAc;AAI7C,YACE,CACE,6BACA,SACE,IAN8B,KAAK,KAAK,GAMN,sBAAsB,MACxD,WAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;AAID,aAAW,MAAM,UAAU,cAAc,WAAW,EAAE,EAAE;GACtD,MAAM,EAAE,sBAAsB,uBAAuB;AAErD,SAAM,OAAO,aAAa;IACxB,cAAc;KACZ;KACA;KACD;IACD;IACD,CAAC;;AAIJ,YACE,CAAC,QAAQ,SAAS,GAFS,KAAK,KAAK,GAAG,mBAEE,KAAK,WAAW,MAAM,CAAC,EACjE;GACE,OAAO;GACP,WAAW;GACZ,CACF;IAEH;EACE;EACA;EACA;EACD,CACF"}
|
|
@@ -4,6 +4,19 @@ import packageJson from "@intlayer/core/package.json" with { type: "json" };
|
|
|
4
4
|
|
|
5
5
|
//#region src/utils/runOnce.ts
|
|
6
6
|
const DEFAULT_RUN_ONCE_OPTIONS = { cacheTimeoutMs: 60 * 1e3 };
|
|
7
|
+
const writeSentinelFile = async (sentinelFilePath, currentTimestamp) => {
|
|
8
|
+
try {
|
|
9
|
+
await mkdir(dirname(sentinelFilePath), { recursive: true });
|
|
10
|
+
const data = {
|
|
11
|
+
version: packageJson.version,
|
|
12
|
+
timestamp: currentTimestamp
|
|
13
|
+
};
|
|
14
|
+
await writeFile(sentinelFilePath, JSON.stringify(data), { flag: "wx" });
|
|
15
|
+
} catch (err) {
|
|
16
|
+
if (err.code === "EEXIST") return;
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
7
20
|
/**
|
|
8
21
|
* Ensures a callback function runs only once within a specified time window across multiple processes.
|
|
9
22
|
* Uses a sentinel file to coordinate execution and prevent duplicate work.
|
|
@@ -59,18 +72,13 @@ const runOnce = async (sentinelFilePath, callback, options) => {
|
|
|
59
72
|
} catch (err) {
|
|
60
73
|
if (err.code === "ENOENT") {} else throw err;
|
|
61
74
|
}
|
|
75
|
+
writeSentinelFile(sentinelFilePath, currentTimestamp);
|
|
62
76
|
try {
|
|
63
|
-
await
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
};
|
|
68
|
-
await writeFile(sentinelFilePath, JSON.stringify(data), { flag: "wx" });
|
|
69
|
-
} catch (err) {
|
|
70
|
-
if (err.code === "EEXIST") return;
|
|
71
|
-
throw err;
|
|
77
|
+
await callback();
|
|
78
|
+
writeSentinelFile(sentinelFilePath, currentTimestamp);
|
|
79
|
+
} catch {
|
|
80
|
+
await unlink(sentinelFilePath);
|
|
72
81
|
}
|
|
73
|
-
await callback();
|
|
74
82
|
};
|
|
75
83
|
|
|
76
84
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runOnce.mjs","names":["
|
|
1
|
+
{"version":3,"file":"runOnce.mjs","names":["data: SentinelData","err: any","cachedVersion: string | undefined"],"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":["import { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport packageJson from '@intlayer/core/package.json' with { type: 'json' };\n\ntype RunOnceOptions = {\n /**\n * The function to execute when the sentinel is not found or is older than the cache timeout.\n */\n onIsCached?: () => void | Promise<void>;\n /**\n * The time window in milliseconds during which the sentinel is considered valid.\n *\n * @default 60000 = 1 minute\n */\n cacheTimeoutMs?: number;\n /**\n * If true, the callback will always run. If undefined, the callback will run only if the sentinel is older than the cache timeout.\n *\n * @default false\n */\n forceRun?: boolean;\n};\n\nconst DEFAULT_RUN_ONCE_OPTIONS = {\n cacheTimeoutMs: 60 * 1000, // 1 minute in milliseconds,\n} satisfies RunOnceOptions;\n\ntype SentinelData = {\n version: string;\n timestamp: number;\n};\n\nconst writeSentinelFile = async (\n sentinelFilePath: string,\n currentTimestamp: number\n) => {\n try {\n // Ensure the directory exists before writing the file\n await mkdir(dirname(sentinelFilePath), { recursive: true });\n\n // O_EXCL ensures only the *first* process can create the file\n const data: SentinelData = {\n version: packageJson.version,\n timestamp: currentTimestamp,\n };\n await writeFile(sentinelFilePath, JSON.stringify(data), { flag: 'wx' });\n } catch (err: any) {\n if (err.code === 'EEXIST') {\n // Another process already created it → we're done\n return;\n }\n throw err; // unexpected FS error\n }\n};\n\n/**\n * Ensures a callback function runs only once within a specified time window across multiple processes.\n * Uses a sentinel file to coordinate execution and prevent duplicate work.\n *\n * @param sentinelFilePath - Path to the sentinel file used for coordination\n * @param callback - The function to execute (should be async)\n * @param options - The options for the runOnce function\n *\n * @example\n * ```typescript\n * await runPrepareIntlayerOnce(\n * '/tmp/intlayer-sentinel',\n * async () => {\n * // Your initialization logic here\n * await prepareIntlayer();\n * },\n * 30 * 1000 // 30 seconds cache\n * );\n * ```\n *\n * @throws {Error} When there are unexpected filesystem errors\n */\nexport const runOnce = async (\n sentinelFilePath: string,\n callback: () => void | Promise<void>,\n options?: RunOnceOptions\n) => {\n const { onIsCached, cacheTimeoutMs, forceRun } = {\n ...DEFAULT_RUN_ONCE_OPTIONS,\n ...(options ?? {}),\n };\n const currentTimestamp = Date.now();\n\n try {\n // Check if sentinel file exists and get its stats\n const sentinelStats = await stat(sentinelFilePath);\n const sentinelAge = currentTimestamp - sentinelStats.mtime.getTime();\n\n // Determine if we should rebuild based on cache age, force flag, or version mismatch\n let shouldRebuild = Boolean(forceRun) || sentinelAge > cacheTimeoutMs!;\n\n if (!shouldRebuild) {\n try {\n const raw = await readFile(sentinelFilePath, 'utf8');\n let cachedVersion: string | undefined;\n try {\n const parsed = JSON.parse(raw) as Partial<SentinelData>;\n cachedVersion = parsed.version;\n } catch {\n // Legacy format (timestamp only). Force a rebuild once to write versioned sentinel.\n cachedVersion = undefined;\n }\n\n if (!cachedVersion || cachedVersion !== packageJson.version) {\n shouldRebuild = true;\n }\n } catch {\n // If we cannot read the file, err on the safe side and rebuild\n shouldRebuild = true;\n }\n }\n\n if (shouldRebuild) {\n try {\n await unlink(sentinelFilePath);\n } catch (err: any) {\n if (err.code !== 'ENOENT') throw err;\n }\n // Fall through to create new sentinel and rebuild\n } else {\n await onIsCached?.();\n // Sentinel is recent and versions match, no need to rebuild\n return;\n }\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n // File doesn't exist, continue to create it\n } else {\n throw err; // unexpected FS error\n }\n }\n\n // Write sentinel file before to block parallel processes\n writeSentinelFile(sentinelFilePath, currentTimestamp);\n\n try {\n await callback();\n\n // Write sentinel file after to ensure the first one has not been removed with cleanOutputDir\n writeSentinelFile(sentinelFilePath, currentTimestamp);\n } catch {\n await unlink(sentinelFilePath); // Remove sentinel file if an error occurs\n }\n};\n"],"mappings":";;;;;AAuBA,MAAM,2BAA2B,EAC/B,gBAAgB,KAAK,KACtB;AAOD,MAAM,oBAAoB,OACxB,kBACA,qBACG;AACH,KAAI;AAEF,QAAM,MAAM,QAAQ,iBAAiB,EAAE,EAAE,WAAW,MAAM,CAAC;EAG3D,MAAMA,OAAqB;GACzB,SAAS,YAAY;GACrB,WAAW;GACZ;AACD,QAAM,UAAU,kBAAkB,KAAK,UAAU,KAAK,EAAE,EAAE,MAAM,MAAM,CAAC;UAChEC,KAAU;AACjB,MAAI,IAAI,SAAS,SAEf;AAEF,QAAM;;;;;;;;;;;;;;;;;;;;;;;;;AA0BV,MAAa,UAAU,OACrB,kBACA,UACA,YACG;CACH,MAAM,EAAE,YAAY,gBAAgB,aAAa;EAC/C,GAAG;EACH,GAAI,WAAW,EAAE;EAClB;CACD,MAAM,mBAAmB,KAAK,KAAK;AAEnC,KAAI;EAGF,MAAM,cAAc,oBADE,MAAM,KAAK,iBAAiB,EACG,MAAM,SAAS;EAGpE,IAAI,gBAAgB,QAAQ,SAAS,IAAI,cAAc;AAEvD,MAAI,CAAC,cACH,KAAI;GACF,MAAM,MAAM,MAAM,SAAS,kBAAkB,OAAO;GACpD,IAAIC;AACJ,OAAI;AAEF,oBADe,KAAK,MAAM,IAAI,CACP;WACjB;AAEN,oBAAgB;;AAGlB,OAAI,CAAC,iBAAiB,kBAAkB,YAAY,QAClD,iBAAgB;UAEZ;AAEN,mBAAgB;;AAIpB,MAAI,cACF,KAAI;AACF,SAAM,OAAO,iBAAiB;WACvBD,KAAU;AACjB,OAAI,IAAI,SAAS,SAAU,OAAM;;OAG9B;AACL,SAAM,cAAc;AAEpB;;UAEKA,KAAU;AACjB,MAAI,IAAI,SAAS,UAAU,OAGzB,OAAM;;AAKV,mBAAkB,kBAAkB,iBAAiB;AAErD,KAAI;AACF,QAAM,UAAU;AAGhB,oBAAkB,kBAAkB,iBAAiB;SAC/C;AACN,QAAM,OAAO,iBAAiB"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { UnmergedDictionaryOutput } from "./writeUnmergedDictionary.js";
|
|
2
2
|
import { MergedDictionaryOutput } from "./writeMergedDictionary.js";
|
|
3
3
|
import { LocalizedDictionaryOutput } from "./writeDynamicDictionary.js";
|
|
4
|
-
import * as
|
|
4
|
+
import * as _intlayer_types0 from "@intlayer/types";
|
|
5
5
|
import { Dictionary } from "@intlayer/types";
|
|
6
6
|
|
|
7
7
|
//#region src/buildIntlayerDictionary/buildIntlayerDictionary.d.ts
|
|
8
8
|
/**
|
|
9
9
|
* This function transpile the bundled code to to make dictionaries as JSON files
|
|
10
10
|
*/
|
|
11
|
-
declare const buildDictionary: (localDictionariesEntries: Dictionary[], configuration?:
|
|
11
|
+
declare const buildDictionary: (localDictionariesEntries: Dictionary[], configuration?: _intlayer_types0.IntlayerConfig, formats?: ("cjs" | "esm")[], importOtherDictionaries?: boolean) => Promise<{
|
|
12
12
|
unmergedDictionaries: UnmergedDictionaryOutput;
|
|
13
13
|
mergedDictionaries: MergedDictionaryOutput;
|
|
14
14
|
dynamicDictionaries: LocalizedDictionaryOutput;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MergedDictionaryOutput } from "./writeMergedDictionary.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _intlayer_types3 from "@intlayer/types";
|
|
3
3
|
import { Dictionary, Locale } from "@intlayer/types";
|
|
4
4
|
|
|
5
5
|
//#region src/buildIntlayerDictionary/writeDynamicDictionary.d.ts
|
|
@@ -12,7 +12,7 @@ type LocalizedDictionaryOutput = Record<string, LocalizedDictionaryResult>;
|
|
|
12
12
|
/**
|
|
13
13
|
* This function generates the content of the dictionary list file
|
|
14
14
|
*/
|
|
15
|
-
declare const generateDictionaryEntryPoint: (localizedDictionariesPathsRecord: LocalizedDictionaryResult, format?: "cjs" | "esm", configuration?:
|
|
15
|
+
declare const generateDictionaryEntryPoint: (localizedDictionariesPathsRecord: LocalizedDictionaryResult, format?: "cjs" | "esm", configuration?: _intlayer_types3.IntlayerConfig) => string;
|
|
16
16
|
/**
|
|
17
17
|
* Write the localized dictionaries to the dictionariesDir
|
|
18
18
|
* @param mergedDictionaries - The merged dictionaries
|
|
@@ -29,7 +29,7 @@ declare const generateDictionaryEntryPoint: (localizedDictionariesPathsRecord: L
|
|
|
29
29
|
* // { key: 'home', content: { ... } },
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
declare const writeDynamicDictionary: (mergedDictionaries: MergedDictionaryOutput, configuration?:
|
|
32
|
+
declare const writeDynamicDictionary: (mergedDictionaries: MergedDictionaryOutput, configuration?: _intlayer_types3.IntlayerConfig, formats?: ("cjs" | "esm")[]) => Promise<LocalizedDictionaryOutput>;
|
|
33
33
|
//#endregion
|
|
34
34
|
export { DictionaryResult, LocalizedDictionaryOutput, LocalizedDictionaryResult, generateDictionaryEntryPoint, writeDynamicDictionary };
|
|
35
35
|
//# sourceMappingURL=writeDynamicDictionary.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { LocalizedDictionaryOutput, LocalizedDictionaryResult } from "./writeDynamicDictionary.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _intlayer_types6 from "@intlayer/types";
|
|
3
3
|
|
|
4
4
|
//#region src/buildIntlayerDictionary/writeFetchDictionary.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* This function generates the content of the dictionary list file
|
|
7
7
|
*/
|
|
8
|
-
declare const generateDictionaryEntryPoint: (localedDictionariesPathsRecord: LocalizedDictionaryResult, format?: "cjs" | "esm", configuration?:
|
|
8
|
+
declare const generateDictionaryEntryPoint: (localedDictionariesPathsRecord: LocalizedDictionaryResult, format?: "cjs" | "esm", configuration?: _intlayer_types6.IntlayerConfig) => string;
|
|
9
9
|
/**
|
|
10
10
|
* Write the localized dictionaries to the dictionariesDir
|
|
11
11
|
* @param mergedDictionaries - The merged dictionaries
|
|
@@ -22,7 +22,7 @@ declare const generateDictionaryEntryPoint: (localedDictionariesPathsRecord: Loc
|
|
|
22
22
|
* // { key: 'home', content: { ... } },
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
declare const writeFetchDictionary: (dynamicDictionaries: LocalizedDictionaryOutput, configuration?:
|
|
25
|
+
declare const writeFetchDictionary: (dynamicDictionaries: LocalizedDictionaryOutput, configuration?: _intlayer_types6.IntlayerConfig, formats?: ("cjs" | "esm")[]) => Promise<LocalizedDictionaryOutput>;
|
|
26
26
|
//#endregion
|
|
27
27
|
export { generateDictionaryEntryPoint, writeFetchDictionary };
|
|
28
28
|
//# sourceMappingURL=writeFetchDictionary.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UnmergedDictionaryOutput } from "./writeUnmergedDictionary.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _intlayer_types1 from "@intlayer/types";
|
|
3
3
|
import { Dictionary } from "@intlayer/types";
|
|
4
4
|
|
|
5
5
|
//#region src/buildIntlayerDictionary/writeMergedDictionary.d.ts
|
|
@@ -24,7 +24,7 @@ type MergedDictionaryOutput = Record<string, MergedDictionaryResult>;
|
|
|
24
24
|
* // { key: 'home', content: { ... } },
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
|
-
declare const writeMergedDictionaries: (groupedDictionaries: UnmergedDictionaryOutput, configuration?:
|
|
27
|
+
declare const writeMergedDictionaries: (groupedDictionaries: UnmergedDictionaryOutput, configuration?: _intlayer_types1.IntlayerConfig) => Promise<MergedDictionaryOutput>;
|
|
28
28
|
//#endregion
|
|
29
29
|
export { MergedDictionaryOutput, MergedDictionaryResult, writeMergedDictionaries };
|
|
30
30
|
//# sourceMappingURL=writeMergedDictionary.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _intlayer_types2 from "@intlayer/types";
|
|
2
2
|
import { Dictionary } from "@intlayer/types";
|
|
3
3
|
|
|
4
4
|
//#region src/buildIntlayerDictionary/writeRemoteDictionary.d.ts
|
|
@@ -23,7 +23,7 @@ type RemoteDictionaryOutput = Record<string, RemoteDictionaryResult>;
|
|
|
23
23
|
* // { key: 'home', content: { ... } },
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
|
-
declare const writeRemoteDictionary: (remoteDictionaries: Dictionary[], configuration?:
|
|
26
|
+
declare const writeRemoteDictionary: (remoteDictionaries: Dictionary[], configuration?: _intlayer_types2.IntlayerConfig) => Promise<RemoteDictionaryOutput>;
|
|
27
27
|
//#endregion
|
|
28
28
|
export { RemoteDictionaryOutput, RemoteDictionaryResult, writeRemoteDictionary };
|
|
29
29
|
//# sourceMappingURL=writeRemoteDictionary.d.ts.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _intlayer_types0 from "@intlayer/types";
|
|
2
2
|
|
|
3
3
|
//#region src/createDictionaryEntryPoint/generateDictionaryListContent.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* This function generates the content of the dictionary list file
|
|
6
6
|
*/
|
|
7
|
-
declare const generateDictionaryListContent: (dictionaries: string[], functionName: string, format?: "cjs" | "esm", configuration?:
|
|
7
|
+
declare const generateDictionaryListContent: (dictionaries: string[], functionName: string, format?: "cjs" | "esm", configuration?: _intlayer_types0.IntlayerConfig) => string;
|
|
8
8
|
//#endregion
|
|
9
9
|
export { generateDictionaryListContent };
|
|
10
10
|
//# sourceMappingURL=generateDictionaryListContent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runOnce.d.ts","names":[],"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":[],"mappings":";KAIK,cAAA;EAAA;
|
|
1
|
+
{"version":3,"file":"runOnce.d.ts","names":[],"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":[],"mappings":";KAIK,cAAA;EAAA;AAyEL;;EAGY,UAAA,CAAA,EAAA,GAAA,GAAA,IAAA,GAxEgB,OAwEhB,CAAA,IAAA,CAAA;EAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAHb,2DAEY,yBACb,mBAAc"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/chokidar",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.2-canary.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.",
|
|
6
6
|
"keywords": [
|
|
@@ -74,13 +74,13 @@
|
|
|
74
74
|
"typecheck": "tsc --noEmit --project tsconfig.types.json"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@intlayer/api": "7.1.
|
|
78
|
-
"@intlayer/config": "7.1.
|
|
79
|
-
"@intlayer/core": "7.1.
|
|
80
|
-
"@intlayer/dictionaries-entry": "7.1.
|
|
81
|
-
"@intlayer/remote-dictionaries-entry": "7.1.
|
|
82
|
-
"@intlayer/types": "7.1.
|
|
83
|
-
"@intlayer/unmerged-dictionaries-entry": "7.1.
|
|
77
|
+
"@intlayer/api": "7.1.2-canary.0",
|
|
78
|
+
"@intlayer/config": "7.1.2-canary.0",
|
|
79
|
+
"@intlayer/core": "7.1.2-canary.0",
|
|
80
|
+
"@intlayer/dictionaries-entry": "7.1.2-canary.0",
|
|
81
|
+
"@intlayer/remote-dictionaries-entry": "7.1.2-canary.0",
|
|
82
|
+
"@intlayer/types": "7.1.2-canary.0",
|
|
83
|
+
"@intlayer/unmerged-dictionaries-entry": "7.1.2-canary.0",
|
|
84
84
|
"chokidar": "3.6.0",
|
|
85
85
|
"crypto-js": "4.2.0",
|
|
86
86
|
"deep-equal": "2.2.3",
|