Skip to main content
Glama
prepareIntlayer.ts7.36 kB
import { stat } from 'node:fs/promises'; import { join } from 'node:path'; import { ANSIColors, cacheDisk, // checkVersionsConsistency, colorize, getAppLogger, } from '@intlayer/config'; import packageJson from '@intlayer/config/package.json' with { type: 'json' }; import type { IntlayerConfig } from '@intlayer/types'; import { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary'; import { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary'; import { cleanOutputDir } from './cleanOutputDir'; import { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint'; import { createModuleAugmentation, createTypes } from './createType/index'; import { listDictionariesWithStats } from './listDictionariesPath'; import { loadDictionaries } from './loadDictionaries/loadDictionaries'; import { runOnce } from './utils/runOnce'; import { isCachedConfigurationUpToDate, writeConfiguration, } from './writeConfiguration'; type PrepareIntlayerOptions = { clean?: boolean; format?: ('cjs' | 'esm')[]; forceRun?: boolean; cacheTimeoutMs?: number; onIsCached?: () => void | Promise<void>; }; const DEFAULT_PREPARE_INTLAYER_OPTIONS = { clean: false, format: ['cjs', 'esm'], cacheTimeoutMs: 1000 * 60 * 60, // 1 hour } satisfies PrepareIntlayerOptions; export const prepareIntlayer = async ( configuration: IntlayerConfig, options?: PrepareIntlayerOptions ) => { const appLogger = getAppLogger(configuration); const sentinelPath = join( configuration.content.cacheDir, 'intlayer-prepared.lock' ); // Clean output dir if the intlayer version has changed const versionCache = cacheDisk(configuration, ['intlayer-version']); const intlayerCacheVersion = await versionCache.get(); const isCorrectVersion = Boolean( intlayerCacheVersion && intlayerCacheVersion === packageJson.version ); const isConfigSimilar = await isCachedConfigurationUpToDate(configuration); // Check if any dictionary has been changed to force a new rebuild const dictionariesWithStats = await listDictionariesWithStats(configuration); let isDictionaryChanged = false; try { // Try catch as sentinel file may not exist yet const sentinelStats = await stat(sentinelPath); isDictionaryChanged = dictionariesWithStats.some( (dictionary) => dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime() ); } catch {} const hasPluginLoadDictionaries = configuration.plugins?.some((plugin) => Boolean(plugin.loadDictionaries) ); // Disable cache if any plugin because it can have custom behavior const { clean, format, forceRun, onIsCached, cacheTimeoutMs } = { ...DEFAULT_PREPARE_INTLAYER_OPTIONS, forceRun: !isCorrectVersion || !isConfigSimilar || isDictionaryChanged || hasPluginLoadDictionaries, ...(options ?? {}), }; // Skip preparation if it has already been done recently await runOnce( sentinelPath, async () => { // comment because of issue with next and webpack // await checkVersionsConsistency(configuration); if (clean || !isCorrectVersion) { await cleanOutputDir(configuration); } await versionCache.set(packageJson.version); const preparationStartMs = Date.now(); appLogger([ 'Preparing Intlayer', colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK), ]); await writeConfiguration(configuration); const configurationWrittenTime = Date.now(); appLogger( [ 'Configuration written', colorize( `(${configurationWrittenTime - preparationStartMs}ms)`, ANSIColors.GREY_DARK ), ], { isVerbose: true, } ); const contentDeclarationPaths = dictionariesWithStats.map( (dictionary) => dictionary.path ); const dictionaries = await loadDictionaries( contentDeclarationPaths, configuration ); const dictionariesLoadedTime = Date.now(); appLogger( [ 'Content loaded', colorize( [ dictionaries.remoteDictionaries.length + dictionaries.pluginDictionaries.length > 0 ? [ `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`, dictionaries.localDictionaries.length > 0 ? `- Local: ${dictionaries.time.localDictionaries}ms` : '', dictionaries.remoteDictionaries.length > 0 ? `- Remote: ${dictionaries.time.remoteDictionaries}ms` : '', dictionaries.pluginDictionaries.length > 0 ? `- Plugin: ${dictionaries.time.pluginDictionaries}ms` : '', `)`, ].join('') : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`, ].join(''), ANSIColors.GREY_DARK ), ], { isVerbose: true, } ); // Build local dictionaries const dictionariesOutput = await buildDictionary( [ ...dictionaries.localDictionaries, ...dictionaries.remoteDictionaries, ...dictionaries.pluginDictionaries, ], configuration, format, false ); // Write remote dictionaries // Used as cache for next fetch await writeRemoteDictionary( dictionaries.remoteDictionaries, configuration ); const dictionariesPaths = Object.values( dictionariesOutput?.mergedDictionaries ?? {} ).map((dictionary) => dictionary.dictionaryPath); await createTypes(dictionariesPaths, configuration); await createDictionaryEntryPoint(configuration); const dictionariesBuiltTime = Date.now(); appLogger([ 'Dictionaries built', colorize( `(${dictionariesBuiltTime - preparationStartMs}ms)`, ANSIColors.GREY_DARK ), ]); await createModuleAugmentation(configuration); const moduleAugmentationBuiltTime = Date.now(); appLogger( [ 'Module augmentation built', colorize( `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`, ANSIColors.GREY_DARK ), ], { isVerbose: true, } ); // Plugin transformation // Allow plugins to post-process the final build output (e.g., write back ICU JSON) for await (const plugin of configuration.plugins ?? []) { const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput; await plugin.afterBuild?.({ dictionaries: { unmergedDictionaries, mergedDictionaries, }, configuration, }); } const preparationElapsedMs = Date.now() - preparationStartMs; appLogger( [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)], { level: 'info', isVerbose: true, } ); }, { forceRun, onIsCached, cacheTimeoutMs, } ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server