@intlayer/chokidar 7.5.6 → 7.5.8
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 +18 -0
- package/dist/assets/initConfig/templates/js.txt +18 -0
- package/dist/assets/initConfig/templates/json.txt +7 -0
- package/dist/assets/initConfig/templates/mjs.txt +18 -0
- package/dist/assets/initConfig/templates/ts.txt +16 -0
- package/dist/cjs/createType/createType.cjs +3 -7
- package/dist/cjs/createType/createType.cjs.map +1 -1
- package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +1 -1
- package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
- package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -3
- package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
- package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +1 -1
- package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/init/index.cjs +131 -0
- package/dist/cjs/init/index.cjs.map +1 -0
- package/dist/cjs/initConfig/index.cjs +42 -0
- package/dist/cjs/initConfig/index.cjs.map +1 -0
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs +3 -3
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
- package/dist/cjs/prepareIntlayer.cjs +1 -1
- package/dist/cjs/prepareIntlayer.cjs.map +1 -1
- package/dist/cjs/transformFiles/transformFiles.cjs.map +1 -1
- package/dist/esm/createType/createType.mjs +3 -7
- package/dist/esm/createType/createType.mjs.map +1 -1
- package/dist/esm/handleAdditionalContentDeclarationFile.mjs +1 -1
- package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
- package/dist/esm/handleContentDeclarationFileChange.mjs +6 -3
- package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
- package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +1 -1
- package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/init/index.mjs +130 -0
- package/dist/esm/init/index.mjs.map +1 -0
- package/dist/esm/initConfig/index.mjs +40 -0
- package/dist/esm/initConfig/index.mjs.map +1 -0
- package/dist/esm/loadDictionaries/loadDictionaries.mjs +3 -3
- package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
- package/dist/esm/prepareIntlayer.mjs +1 -1
- package/dist/esm/prepareIntlayer.mjs.map +1 -1
- package/dist/esm/transformFiles/transformFiles.mjs +2 -2
- package/dist/esm/transformFiles/transformFiles.mjs.map +1 -1
- package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts +2 -2
- package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts +3 -3
- package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts +3 -3
- package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeMergedDictionary.d.ts +2 -2
- package/dist/types/buildIntlayerDictionary/writeMergedDictionary.d.ts.map +1 -1
- package/dist/types/buildIntlayerDictionary/writeRemoteDictionary.d.ts +2 -2
- package/dist/types/buildIntlayerDictionary/writeRemoteDictionary.d.ts.map +1 -1
- package/dist/types/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts +2 -2
- package/dist/types/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts.map +1 -1
- package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts +2 -2
- package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts.map +1 -1
- package/dist/types/createType/createType.d.ts +1 -1
- package/dist/types/createType/createType.d.ts.map +1 -1
- package/dist/types/formatDictionary.d.ts +15 -15
- package/dist/types/index.d.ts +2 -1
- package/dist/types/init/index.d.ts +8 -0
- package/dist/types/init/index.d.ts.map +1 -0
- package/dist/types/initConfig/index.d.ts +11 -0
- package/dist/types/initConfig/index.d.ts.map +1 -0
- package/dist/types/transformFiles/transformFiles.d.ts.map +1 -1
- package/dist/types/utils/getFormatFromExtension.d.ts.map +1 -1
- package/package.json +10 -10
|
@@ -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 {\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 { 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 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 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 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 hasPluginLoadDictionaries = configuration.plugins?.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 } = {\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 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":"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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 {\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 { 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 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 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 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 hasPluginLoadDictionaries = configuration.plugins?.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 } = {\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 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 dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, 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":";;;;;;;;;;;;;;;;;;AAgCA,MAAM,mCAAmC;CACvC,OAAO;CACP,QAAQ,CAAC,OAAO,MAAM;CACtB,gBAAgB,MAAO,KAAK;CAC7B;AAED,MAAa,kBAAkB,OAC7B,eACA,YACG;CACH,MAAM,+CAAyB,cAAc;CAE7C,MAAM,mCACJ,cAAc,QAAQ,UACtB,yBACD;CAED,MAAM,+CAAyB,eAAe,CAAC,mBAAmB,CAAC;CACnE,MAAM,uBAAuB,MAAM,aAAa,KAAK;CACrD,MAAM,mBAAmB,QACvB,wBAAwB,yBAAyBA,sCAAY,QAC9D;CAED,MAAM,kBAAkB,MAAMC,+DAA8B,cAAc;CAG1E,MAAM,wBAAwB,MAAMC,uDAA0B,cAAc;CAC5E,IAAI,sBAAsB;AAC1B,KAAI;EAEF,MAAM,gBAAgB,iCAAW,aAAa;AAC9C,wBAAsB,sBAAsB,MACzC,eACC,WAAW,MAAM,MAAM,SAAS,GAAG,cAAc,MAAM,SAAS,CACnE;SACK;CAER,MAAM,4BAA4B,cAAc,SAAS,MAAM,WAC7D,QAAQ,OAAO,iBAAiB,CACjC;CAED,MAAM,EAAE,OAAO,QAAQ,UAAU,YAAY,mBAAmB;EAC9D,GAAG;EACH,UACE,CAAC,oBACD,CAAC,mBACD,uBACA;EACF,GAAI,WAAW,EAAE;EAClB;AAGD,OAAMC,8BACJ,cACA,YAAY;AAIV,MAAI,SAAS,CAAC,iBACZ,OAAMC,sCAAe,cAAc;AAGrC,QAAM,aAAa,IAAIJ,sCAAY,QAAQ;EAE3C,MAAM,qBAAqB,KAAK,KAAK;AAErC,YAAU,CACR,qDACS,KAAKA,sCAAY,QAAQ,IAAIK,4BAAW,UAAU,CAC5D,CAAC;AAEF,QAAMC,oDAAmB,cAAc;EAEvC,MAAM,2BAA2B,KAAK,KAAK;AAE3C,YACE,CACE,wDAEE,IAAI,2BAA2B,mBAAmB,MAClDD,4BAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;EAMD,MAAM,eAAe,MAAME,2DAJK,sBAAsB,KACnD,eAAe,WAAW,KAC5B,EAIC,cACD;EAED,MAAM,yBAAyB,KAAK,KAAK;AAEzC,YACE,CACE,iDAEE,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,EACVF,4BAAW,UACZ,CACF,EACD,EACE,WAAW,MACZ,CACF;EAGD,MAAM,qBAAqB,MAAMG,wEAC/B;GACE,GAAG,aAAa;GAChB,GAAG,aAAa;GAChB,GAAG,aAAa;GACjB,EACD,eACA,QACA,MACD;AAID,QAAMC,4EACJ,aAAa,oBACb,cACD;AAMD,QAAMC,0CAJsB,OAAO,OACjC,oBAAoB,sBAAsB,EAAE,CAC7C,CAAC,KAAK,eAAe,WAAW,WAAW,EAEL,cAAc;AAErD,QAAMC,yFAA2B,cAAc;EAE/C,MAAM,wBAAwB,KAAK,KAAK;AAExC,YAAU,CACR,qDAEE,IAAI,wBAAwB,mBAAmB,MAC/CN,4BAAW,UACZ,CACF,CAAC;AAEF,QAAMO,qEAAyB,cAAc;AAI7C,YACE,CACE,4DAEE,IAN8B,KAAK,KAAK,GAMN,sBAAsB,MACxDP,4BAAW,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,uCAAiB,GAFS,KAAK,KAAK,GAAG,mBAEE,KAAKA,4BAAW,MAAM,CAAC,EACjE;GACE,OAAO;GACP,WAAW;GACZ,CACF;IAEH;EACE;EACA;EACA;EACD,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformFiles.cjs","names":["dictionary: Dictionary","multilingualContent: Record<string, TranslationNode>","writeContentDeclaration","extractedContent: Record<string, string>","replacements: TsReplacement[]","Node","sourceFile: SourceFile","SyntaxKind","Project","extractDictionaryKey","fs","extractedContent: Record<string, string> | null","error: any","ANSIColors","detectFormatCommand"],"sources":["../../../src/transformFiles/transformFiles.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { basename, dirname, extname, join, relative, resolve } from 'node:path';\nimport {\n ANSIColors,\n camelCaseToKebabCase,\n colorizePath,\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type { Dictionary, IntlayerConfig } from '@intlayer/types';\nimport { Node, Project, type SourceFile, SyntaxKind } from 'ts-morph';\nimport { writeContentDeclaration } from '../writeContentDeclaration';\nimport { detectFormatCommand } from '../writeContentDeclaration/detectFormatCommand';\nimport { extractDictionaryKey } from './extractDictionaryKey';\n\n// ==========================================\n// 1. Shared Utilities (exported for reuse in babel plugin)\n// ==========================================\n\n/**\n * Attributes that should be extracted for localization\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n];\n\n/**\n * Default function to determine if a string should be extracted for localization\n */\nexport const shouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed) return false;\n if (!trimmed.includes(' ')) return false;\n // Starts with Capital letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n // Filter out template logic identifiers (simple check)\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n return true;\n};\n\n/**\n * Generate a unique key from text for use as a dictionary key\n */\nexport const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n let key = text\n .replace(/\\s+/g, ' ')\n .replace(/_+/g, ' ')\n .replace(/-+/g, ' ')\n .replace(/[^a-zA-Z0-9 ]/g, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (!key) key = 'content';\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n\n/**\n * Translation node structure used in multilingual dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\nconst writeContentHelper = async (\n extractedContent: Record<string, string>,\n componentKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n outputDir?: string\n) => {\n const { defaultLocale } = configuration.internationalization;\n const { baseDir, fileExtensions } = configuration.content;\n\n const isPerLocaleFile = configuration?.dictionary?.locale;\n\n const dirName = outputDir ? resolve(outputDir) : dirname(filePath);\n const ext = extname(filePath);\n const baseName = basename(filePath, ext);\n const contentBaseName = baseName.charAt(0).toLowerCase() + baseName.slice(1);\n\n const contentFilePath = join(\n dirName,\n `${contentBaseName}.${fileExtensions[0]}`\n );\n const relativeContentFilePath = relative(baseDir, contentFilePath);\n\n let dictionary: Dictionary;\n\n if (isPerLocaleFile) {\n // Per-locale format: simple string content with locale property\n dictionary = {\n key: componentKey,\n content: extractedContent,\n locale: defaultLocale,\n filePath: relativeContentFilePath,\n };\n } else {\n // Multilingual format: content wrapped in translation nodes, no locale property\n const multilingualContent: Record<string, TranslationNode> = {};\n for (const [key, value] of Object.entries(extractedContent)) {\n multilingualContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n\n dictionary = {\n key: componentKey,\n content: multilingualContent,\n filePath: relativeContentFilePath,\n };\n }\n\n const relativeDir = relative(baseDir, dirName);\n await writeContentDeclaration(dictionary, configuration, {\n newDictionariesPath: relativeDir,\n });\n\n return contentFilePath;\n};\n\ntype TsReplacement = {\n node: Node;\n key: string;\n type: 'jsx-text' | 'jsx-attribute' | 'string-literal';\n};\n\nconst extractTsContent = (\n sourceFile: SourceFile,\n existingKeys: Set<string>\n): {\n extractedContent: Record<string, string>;\n replacements: TsReplacement[];\n} => {\n const extractedContent: Record<string, string> = {};\n const replacements: TsReplacement[] = [];\n\n sourceFile.forEachDescendant((node) => {\n // 1. JSX Text\n if (Node.isJsxText(node)) {\n const text = node.getText();\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.replace(/\\s+/g, ' ').trim();\n replacements.push({ node, key, type: 'jsx-text' });\n }\n }\n\n // 2. JSX Attributes\n else if (Node.isJsxAttribute(node)) {\n const name = node.getNameNode().getText();\n if (ATTRIBUTES_TO_EXTRACT.includes(name)) {\n const initializer = node.getInitializer();\n if (Node.isStringLiteral(initializer)) {\n const text = initializer.getLiteralValue();\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n replacements.push({ node, key, type: 'jsx-attribute' });\n }\n }\n }\n }\n\n // 3. String Literals (Variables, Arrays, etc.)\n else if (Node.isStringLiteral(node)) {\n const text = node.getLiteralValue();\n if (shouldExtract(text)) {\n const parent = node.getParent();\n\n // Skip if inside ImportDeclaration\n if (\n parent?.getKindName() === 'ImportDeclaration' ||\n parent?.getKindName() === 'ImportSpecifier' ||\n parent?.getKindName() === 'ModuleSpecifier'\n ) {\n return;\n }\n\n // Skip if it's a JSX Attribute value (handled above)\n if (Node.isJsxAttribute(parent)) return;\n\n // Skip console.log\n if (Node.isCallExpression(parent)) {\n const expression = parent.getExpression();\n if (expression.getText().includes('console.log')) return;\n }\n\n // Skip Object Keys: { key: \"value\" } -> \"key\" is PropertyAssignment name if not computed\n if (Node.isPropertyAssignment(parent)) {\n if (parent.getNameNode() === node) return; // It's the key\n }\n\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n replacements.push({ node, key, type: 'string-literal' });\n }\n }\n });\n\n return { extractedContent, replacements };\n};\n\n// ==========================================\n// 2. React (TS-Morph) Strategy\n// ==========================================\n\nconst processReactFile = async (\n filePath: string,\n componentKey: string,\n packageName: string,\n project: Project,\n save: boolean = true\n) => {\n let sourceFile: SourceFile;\n try {\n sourceFile = project.addSourceFileAtPath(filePath);\n } catch {\n sourceFile = project.getSourceFileOrThrow(filePath);\n }\n\n const existingKeys = new Set<string>();\n const { extractedContent, replacements } = extractTsContent(\n sourceFile,\n existingKeys\n );\n\n if (Object.keys(extractedContent).length === 0) return null;\n\n for (const { node, key, type } of replacements) {\n if (type === 'jsx-text' && Node.isJsxText(node)) {\n node.replaceWithText(`{content.${key}}`);\n } else if (type === 'jsx-attribute' && Node.isJsxAttribute(node)) {\n node.setInitializer(`{content.${key}.value}`);\n } else if (type === 'string-literal' && Node.isStringLiteral(node)) {\n // For React/JS variables, we usually want the value\n node.replaceWithText(`content.${key}.value`);\n }\n }\n\n // Inject hook\n const importDecl = sourceFile.getImportDeclaration(\n (d) => d.getModuleSpecifierValue() === packageName\n );\n if (!importDecl) {\n sourceFile.addImportDeclaration({\n namedImports: ['useIntlayer'],\n moduleSpecifier: packageName,\n });\n } else if (\n !importDecl.getNamedImports().some((n) => n.getName() === 'useIntlayer')\n ) {\n importDecl.addNamedImport('useIntlayer');\n }\n\n // Insert hook at start of component\n sourceFile.getFunctions().forEach((f) => {\n f.getBody()\n ?.asKind(SyntaxKind.Block)\n ?.insertStatements(0, `const content = useIntlayer(\"${componentKey}\");`);\n });\n\n // Also handle const/arrow components\n sourceFile.getVariableDeclarations().forEach((v) => {\n const init = v.getInitializer();\n if (Node.isArrowFunction(init) || Node.isFunctionExpression(init)) {\n const body = init.getBody();\n if (Node.isBlock(body)) {\n // Heuristic: check if it returns JSX or uses hooks\n if (\n body.getText().includes('return') ||\n body.getText().includes('use')\n ) {\n body.insertStatements(\n 0,\n `const content = useIntlayer(\"${componentKey}\");`\n );\n }\n }\n }\n });\n\n if (save) {\n await sourceFile.save();\n }\n return extractedContent;\n};\n\n// ==========================================\n// 5. Main Dispatcher\n// ==========================================\n\nexport type PackageName =\n | 'next-intlayer'\n | 'react-intlayer'\n | 'vue-intlayer'\n | 'svelte-intlayer'\n | 'preact-intlayer'\n | 'solid-intlayer'\n | 'angular-intlayer'\n | 'express-intlayer';\n\nexport type ExtractIntlayerOptions = {\n configOptions?: GetConfigurationOptions;\n outputDir?: string;\n codeOnly?: boolean;\n declarationOnly?: boolean;\n};\n\nexport const extractIntlayer = async (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions,\n project?: Project\n) => {\n const saveComponent = !options?.declarationOnly;\n const writeContent = !options?.codeOnly;\n\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n const { baseDir } = configuration.content;\n\n // Setup Project for TS/React files if needed\n const _project =\n project || new Project({ skipAddingFilesFromTsConfig: true });\n\n const baseName = extractDictionaryKey(\n filePath,\n (await fs.readFile(filePath)).toString()\n );\n const componentKey = camelCaseToKebabCase(baseName);\n const ext = extname(filePath);\n\n let extractedContent: Record<string, string> | null = null;\n\n if (ext === '.vue') {\n try {\n const { processVueFile } = (await import(\n '@intlayer/vue-transformer'\n )) as any;\n extractedContent = await processVueFile(\n filePath,\n componentKey,\n packageName,\n {\n generateKey,\n shouldExtract,\n extractTsContent,\n },\n saveComponent\n );\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/vue-transformer', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n throw error;\n }\n } else if (ext === '.svelte') {\n try {\n const { processSvelteFile } = (await import(\n '@intlayer/svelte-transformer'\n )) as any;\n extractedContent = await processSvelteFile(\n filePath,\n componentKey,\n packageName,\n {\n generateKey,\n shouldExtract,\n extractTsContent,\n },\n saveComponent\n );\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/svelte-transformer', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n throw error;\n }\n } else if (['.tsx', '.jsx', '.ts', '.js'].includes(ext)) {\n extractedContent = await processReactFile(\n filePath,\n componentKey,\n packageName,\n _project,\n saveComponent\n );\n }\n\n if (!extractedContent) {\n appLogger(`No extractable text found in ${baseName}`);\n return;\n }\n\n // Shared Write Logic\n if (writeContent) {\n const contentFilePath = await writeContentHelper(\n extractedContent,\n componentKey,\n filePath,\n configuration,\n options?.outputDir\n );\n\n const relativeContentFilePath = relative(\n configuration.content.baseDir,\n contentFilePath\n );\n appLogger(`Created content file: ${colorizePath(relativeContentFilePath)}`);\n }\n\n // Optional: Format\n if (saveComponent) {\n try {\n const formatCommand = detectFormatCommand(configuration);\n if (formatCommand) {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'ignore', // Silent\n cwd: baseDir,\n });\n }\n } catch {\n // Ignore format errors\n }\n\n appLogger(\n `Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n};\n\nexport const transformFiles = async (\n filePaths: string[],\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n) => {\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const project = new Project({\n skipAddingFilesFromTsConfig: true,\n });\n\n for (const filePath of filePaths) {\n try {\n await extractIntlayer(filePath, packageName, options, project);\n } catch (error) {\n appLogger(`Failed to transform ${filePath}: ${(error as Error).message}`);\n }\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transformFiles.cjs","names":["dictionary: Dictionary","multilingualContent: Record<string, TranslationNode>","writeContentDeclaration","extractedContent: Record<string, string>","replacements: TsReplacement[]","Node","sourceFile: SourceFile","SyntaxKind","Project","extractDictionaryKey","fs","extractedContent: Record<string, string> | null","error: any","ANSIColors","detectFormatCommand"],"sources":["../../../src/transformFiles/transformFiles.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { basename, dirname, extname, join, relative, resolve } from 'node:path';\nimport {\n ANSIColors,\n camelCaseToKebabCase,\n colorizePath,\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type { Dictionary, IntlayerConfig } from '@intlayer/types';\nimport { Node, Project, type SourceFile, SyntaxKind } from 'ts-morph';\nimport { writeContentDeclaration } from '../writeContentDeclaration';\nimport { detectFormatCommand } from '../writeContentDeclaration/detectFormatCommand';\nimport { extractDictionaryKey } from './extractDictionaryKey';\n\n// ==========================================\n// 1. Shared Utilities (exported for reuse in babel plugin)\n// ==========================================\n\n/**\n * Attributes that should be extracted for localization\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n];\n\n/**\n * Default function to determine if a string should be extracted for localization\n */\nexport const shouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed) return false;\n if (!trimmed.includes(' ')) return false;\n // Starts with Capital letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n // Filter out template logic identifiers (simple check)\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n return true;\n};\n\n/**\n * Generate a unique key from text for use as a dictionary key\n */\nexport const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n let key = text\n .replace(/\\s+/g, ' ')\n .replace(/_+/g, ' ')\n .replace(/-+/g, ' ')\n .replace(/[^a-zA-Z0-9 ]/g, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (!key) key = 'content';\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n\n/**\n * Translation node structure used in multilingual dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\nconst writeContentHelper = async (\n extractedContent: Record<string, string>,\n componentKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n outputDir?: string\n) => {\n const { defaultLocale } = configuration.internationalization;\n const { baseDir, fileExtensions } = configuration.content;\n\n const isPerLocaleFile = configuration?.dictionary?.locale;\n\n const dirName = outputDir ? resolve(outputDir) : dirname(filePath);\n const ext = extname(filePath);\n const baseName = basename(filePath, ext);\n const contentBaseName = baseName.charAt(0).toLowerCase() + baseName.slice(1);\n\n const contentFilePath = join(\n dirName,\n `${contentBaseName}.${fileExtensions[0]}`\n );\n const relativeContentFilePath = relative(baseDir, contentFilePath);\n\n let dictionary: Dictionary;\n\n if (isPerLocaleFile) {\n // Per-locale format: simple string content with locale property\n dictionary = {\n key: componentKey,\n content: extractedContent,\n locale: defaultLocale,\n filePath: relativeContentFilePath,\n };\n } else {\n // Multilingual format: content wrapped in translation nodes, no locale property\n const multilingualContent: Record<string, TranslationNode> = {};\n for (const [key, value] of Object.entries(extractedContent)) {\n multilingualContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n\n dictionary = {\n key: componentKey,\n content: multilingualContent,\n filePath: relativeContentFilePath,\n };\n }\n\n const relativeDir = relative(baseDir, dirName);\n await writeContentDeclaration(dictionary, configuration, {\n newDictionariesPath: relativeDir,\n });\n\n return contentFilePath;\n};\n\ntype TsReplacement = {\n node: Node;\n key: string;\n type: 'jsx-text' | 'jsx-attribute' | 'string-literal';\n};\n\nconst extractTsContent = (\n sourceFile: SourceFile,\n existingKeys: Set<string>\n): {\n extractedContent: Record<string, string>;\n replacements: TsReplacement[];\n} => {\n const extractedContent: Record<string, string> = {};\n const replacements: TsReplacement[] = [];\n\n sourceFile.forEachDescendant((node) => {\n // 1. JSX Text\n if (Node.isJsxText(node)) {\n const text = node.getText();\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.replace(/\\s+/g, ' ').trim();\n replacements.push({ node, key, type: 'jsx-text' });\n }\n }\n\n // 2. JSX Attributes\n else if (Node.isJsxAttribute(node)) {\n const name = node.getNameNode().getText();\n if (ATTRIBUTES_TO_EXTRACT.includes(name)) {\n const initializer = node.getInitializer();\n if (Node.isStringLiteral(initializer)) {\n const text = initializer.getLiteralValue();\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n replacements.push({ node, key, type: 'jsx-attribute' });\n }\n }\n }\n }\n\n // 3. String Literals (Variables, Arrays, etc.)\n else if (Node.isStringLiteral(node)) {\n const text = node.getLiteralValue();\n if (shouldExtract(text)) {\n const parent = node.getParent();\n\n // Skip if inside ImportDeclaration\n if (\n parent?.getKindName() === 'ImportDeclaration' ||\n parent?.getKindName() === 'ImportSpecifier' ||\n parent?.getKindName() === 'ModuleSpecifier'\n ) {\n return;\n }\n\n // Skip if it's a JSX Attribute value (handled above)\n if (Node.isJsxAttribute(parent)) return;\n\n // Skip console.log\n if (Node.isCallExpression(parent)) {\n const expression = parent.getExpression();\n if (expression.getText().includes('console.log')) return;\n }\n\n // Skip Object Keys: { key: \"value\" } -> \"key\" is PropertyAssignment name if not computed\n if (Node.isPropertyAssignment(parent)) {\n if (parent.getNameNode() === node) return; // It's the key\n }\n\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n replacements.push({ node, key, type: 'string-literal' });\n }\n }\n });\n\n return { extractedContent, replacements };\n};\n\n// ==========================================\n// 2. React (TS-Morph) Strategy\n// ==========================================\n\nconst processReactFile = async (\n filePath: string,\n componentKey: string,\n packageName: string,\n project: Project,\n save: boolean = true\n) => {\n let sourceFile: SourceFile;\n try {\n sourceFile = project.addSourceFileAtPath(filePath);\n } catch {\n sourceFile = project.getSourceFileOrThrow(filePath);\n }\n\n const existingKeys = new Set<string>();\n const { extractedContent, replacements } = extractTsContent(\n sourceFile,\n existingKeys\n );\n\n if (Object.keys(extractedContent).length === 0) return null;\n\n for (const { node, key, type } of replacements) {\n if (type === 'jsx-text' && Node.isJsxText(node)) {\n node.replaceWithText(`{content.${key}}`);\n } else if (type === 'jsx-attribute' && Node.isJsxAttribute(node)) {\n node.setInitializer(`{content.${key}.value}`);\n } else if (type === 'string-literal' && Node.isStringLiteral(node)) {\n // For React/JS variables, we usually want the value\n node.replaceWithText(`content.${key}.value`);\n }\n }\n\n // Inject hook\n const importDecl = sourceFile.getImportDeclaration(\n (d) => d.getModuleSpecifierValue() === packageName\n );\n if (!importDecl) {\n sourceFile.addImportDeclaration({\n namedImports: ['useIntlayer'],\n moduleSpecifier: packageName,\n });\n } else if (\n !importDecl.getNamedImports().some((n) => n.getName() === 'useIntlayer')\n ) {\n importDecl.addNamedImport('useIntlayer');\n }\n\n // Insert hook at start of component\n sourceFile.getFunctions().forEach((f) => {\n f.getBody()\n ?.asKind(SyntaxKind.Block)\n ?.insertStatements(0, `const content = useIntlayer(\"${componentKey}\");`);\n });\n\n // Also handle const/arrow components\n sourceFile.getVariableDeclarations().forEach((v) => {\n const init = v.getInitializer();\n if (Node.isArrowFunction(init) || Node.isFunctionExpression(init)) {\n const body = init.getBody();\n if (Node.isBlock(body)) {\n // Heuristic: check if it returns JSX or uses hooks\n if (\n body.getText().includes('return') ||\n body.getText().includes('use')\n ) {\n body.insertStatements(\n 0,\n `const content = useIntlayer(\"${componentKey}\");`\n );\n }\n }\n }\n });\n\n if (save) {\n await sourceFile.save();\n }\n return extractedContent;\n};\n\n// ==========================================\n// 5. Main Dispatcher\n// ==========================================\n\nexport type PackageName =\n | 'next-intlayer'\n | 'react-intlayer'\n | 'vue-intlayer'\n | 'svelte-intlayer'\n | 'preact-intlayer'\n | 'solid-intlayer'\n | 'angular-intlayer'\n | 'express-intlayer';\n\nexport type ExtractIntlayerOptions = {\n configOptions?: GetConfigurationOptions;\n outputDir?: string;\n codeOnly?: boolean;\n declarationOnly?: boolean;\n};\n\nexport const extractIntlayer = async (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions,\n project?: Project\n) => {\n const saveComponent = !options?.declarationOnly;\n const writeContent = !options?.codeOnly;\n\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n const { baseDir } = configuration.content;\n\n // Setup Project for TS/React files if needed\n const _project =\n project || new Project({ skipAddingFilesFromTsConfig: true });\n\n const baseName = extractDictionaryKey(\n filePath,\n (await fs.readFile(filePath)).toString()\n );\n const componentKey = camelCaseToKebabCase(baseName);\n const ext = extname(filePath);\n\n let extractedContent: Record<string, string> | null = null;\n\n if (ext === '.vue') {\n try {\n const { processVueFile } = await import('@intlayer/vue-transformer');\n extractedContent = await processVueFile(\n filePath,\n componentKey,\n packageName,\n {\n generateKey,\n shouldExtract,\n extractTsContent,\n },\n saveComponent\n );\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/vue-transformer', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n throw error;\n }\n } else if (ext === '.svelte') {\n try {\n const { processSvelteFile } = (await import(\n '@intlayer/svelte-transformer'\n )) as any;\n extractedContent = await processSvelteFile(\n filePath,\n componentKey,\n packageName,\n {\n generateKey,\n shouldExtract,\n extractTsContent,\n },\n saveComponent\n );\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/svelte-transformer', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n throw error;\n }\n } else if (['.tsx', '.jsx', '.ts', '.js'].includes(ext)) {\n extractedContent = await processReactFile(\n filePath,\n componentKey,\n packageName,\n _project,\n saveComponent\n );\n }\n\n if (!extractedContent) {\n appLogger(`No extractable text found in ${baseName}`);\n return;\n }\n\n // Shared Write Logic\n if (writeContent) {\n const contentFilePath = await writeContentHelper(\n extractedContent,\n componentKey,\n filePath,\n configuration,\n options?.outputDir\n );\n\n const relativeContentFilePath = relative(\n configuration.content.baseDir,\n contentFilePath\n );\n appLogger(`Created content file: ${colorizePath(relativeContentFilePath)}`);\n }\n\n // Optional: Format\n if (saveComponent) {\n try {\n const formatCommand = detectFormatCommand(configuration);\n if (formatCommand) {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'ignore', // Silent\n cwd: baseDir,\n });\n }\n } catch {\n // Ignore format errors\n }\n\n appLogger(\n `Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n};\n\nexport const transformFiles = async (\n filePaths: string[],\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n) => {\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const project = new Project({\n skipAddingFilesFromTsConfig: true,\n });\n\n for (const filePath of filePaths) {\n try {\n await extractIntlayer(filePath, packageName, options, project);\n } catch (error) {\n appLogger(`Failed to transform ${filePath}: ${(error as Error).message}`);\n }\n }\n};\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { parallelize } from "../utils/parallelize.mjs";
|
|
2
2
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
-
import { clearModuleCache, getProjectRequire } from "@intlayer/config";
|
|
5
4
|
|
|
6
5
|
//#region src/createType/createType.ts
|
|
7
6
|
const generateTypeScriptType = (dictionary) => {
|
|
@@ -10,14 +9,11 @@ const generateTypeScriptType = (dictionary) => {
|
|
|
10
9
|
/**
|
|
11
10
|
* This function generates a TypeScript type definition from a JSON object
|
|
12
11
|
*/
|
|
13
|
-
const createTypes = async (
|
|
14
|
-
const {
|
|
12
|
+
const createTypes = async (dictionaries, configuration) => {
|
|
13
|
+
const { content } = configuration;
|
|
15
14
|
const { typesDir } = content;
|
|
16
15
|
await mkdir(typesDir, { recursive: true });
|
|
17
|
-
return (await parallelize(
|
|
18
|
-
const requireFunction = build.require ?? getProjectRequire();
|
|
19
|
-
clearModuleCache(dictionaryPath);
|
|
20
|
-
const dictionary = requireFunction(dictionaryPath);
|
|
16
|
+
return (await parallelize(dictionaries, async (dictionary) => {
|
|
21
17
|
if (!dictionary.key) return;
|
|
22
18
|
const typeDefinition = generateTypeScriptType(dictionary);
|
|
23
19
|
const outputPath = resolve(typesDir, `${dictionary.key}.ts`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createType.mjs","names":["
|
|
1
|
+
{"version":3,"file":"createType.mjs","names":["typeDefinition: string","outputPath: string"],"sources":["../../../src/createType/createType.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport type { Dictionary, IntlayerConfig } from '@intlayer/types';\nimport { parallelize } from '../utils/parallelize';\n\nexport const generateTypeScriptType = (dictionary: Dictionary) => {\n const jsonString = JSON.stringify(dictionary, null, 2);\n\n return `/* eslint-disable */\\nexport default ${jsonString} as const;\\n`;\n};\n/**\n * This function generates a TypeScript type definition from a JSON object\n */\nexport const createTypes = async (\n dictionaries: Dictionary[],\n configuration: IntlayerConfig\n): Promise<string[]> => {\n const { content } = configuration;\n const { typesDir } = content;\n\n // Create type folders if they don't exist\n await mkdir(typesDir, { recursive: true });\n\n const results = await parallelize(\n dictionaries,\n async (dictionary): Promise<string | undefined> => {\n if (!dictionary.key) {\n return undefined;\n }\n\n const typeDefinition: string = generateTypeScriptType(dictionary);\n\n const outputPath: string = resolve(typesDir, `${dictionary.key}.ts`);\n\n await writeFile(outputPath, typeDefinition);\n\n return outputPath;\n }\n );\n\n return results.filter(Boolean) as string[];\n};\n"],"mappings":";;;;;AAKA,MAAa,0BAA0B,eAA2B;AAGhE,QAAO,wCAFY,KAAK,UAAU,YAAY,MAAM,EAAE,CAEI;;;;;AAK5D,MAAa,cAAc,OACzB,cACA,kBACsB;CACtB,MAAM,EAAE,YAAY;CACpB,MAAM,EAAE,aAAa;AAGrB,OAAM,MAAM,UAAU,EAAE,WAAW,MAAM,CAAC;AAmB1C,SAjBgB,MAAM,YACpB,cACA,OAAO,eAA4C;AACjD,MAAI,CAAC,WAAW,IACd;EAGF,MAAMA,iBAAyB,uBAAuB,WAAW;EAEjE,MAAMC,aAAqB,QAAQ,UAAU,GAAG,WAAW,IAAI,KAAK;AAEpE,QAAM,UAAU,YAAY,eAAe;AAE3C,SAAO;GAEV,EAEc,OAAO,QAAQ"}
|
|
@@ -11,7 +11,7 @@ const handleAdditionalContentDeclarationFile = async (filePath, config) => {
|
|
|
11
11
|
const appLogger = getAppLogger(config);
|
|
12
12
|
appLogger(`Additional file detected: ${formatPath(filePath)}`, { isVerbose: true });
|
|
13
13
|
const dictionariesOutput = await buildDictionary(await loadLocalDictionaries(filePath, config), config);
|
|
14
|
-
await createTypes(Object.values(dictionariesOutput?.mergedDictionaries ?? {}).map((dictionary) => dictionary.
|
|
14
|
+
await createTypes(Object.values(dictionariesOutput?.mergedDictionaries ?? {}).map((dictionary) => dictionary.dictionary), config);
|
|
15
15
|
await createDictionaryEntryPoint(config);
|
|
16
16
|
appLogger("Dictionaries built", { isVerbose: true });
|
|
17
17
|
createModuleAugmentation(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleAdditionalContentDeclarationFile.mjs","names":[],"sources":["../../src/handleAdditionalContentDeclarationFile.ts"],"sourcesContent":["import { getAppLogger } from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { loadLocalDictionaries } from './loadDictionaries/loadLocalDictionaries';\nimport { formatPath } from './utils/formatter';\n\nexport const handleAdditionalContentDeclarationFile = async (\n filePath: string,\n config: IntlayerConfig\n) => {\n const appLogger = getAppLogger(config);\n\n // Process the file with the functionToRun\n appLogger(`Additional file detected: ${formatPath(filePath)}`, {\n isVerbose: true,\n });\n\n const localeDictionaries = await loadLocalDictionaries(filePath, config);\n\n const dictionariesOutput = await buildDictionary(localeDictionaries, config);\n\n const
|
|
1
|
+
{"version":3,"file":"handleAdditionalContentDeclarationFile.mjs","names":[],"sources":["../../src/handleAdditionalContentDeclarationFile.ts"],"sourcesContent":["import { getAppLogger } from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { loadLocalDictionaries } from './loadDictionaries/loadLocalDictionaries';\nimport { formatPath } from './utils/formatter';\n\nexport const handleAdditionalContentDeclarationFile = async (\n filePath: string,\n config: IntlayerConfig\n) => {\n const appLogger = getAppLogger(config);\n\n // Process the file with the functionToRun\n appLogger(`Additional file detected: ${formatPath(filePath)}`, {\n isVerbose: true,\n });\n\n const localeDictionaries = await loadLocalDictionaries(filePath, config);\n\n const dictionariesOutput = await buildDictionary(localeDictionaries, config);\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, config);\n\n await createDictionaryEntryPoint(config);\n\n appLogger('Dictionaries built', {\n isVerbose: true,\n });\n\n createModuleAugmentation(config);\n\n appLogger('Module augmentation built', {\n isVerbose: true,\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 config.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration: config,\n });\n }\n};\n"],"mappings":";;;;;;;;;AAQA,MAAa,yCAAyC,OACpD,UACA,WACG;CACH,MAAM,YAAY,aAAa,OAAO;AAGtC,WAAU,6BAA6B,WAAW,SAAS,IAAI,EAC7D,WAAW,MACZ,CAAC;CAIF,MAAM,qBAAqB,MAAM,gBAFN,MAAM,sBAAsB,UAAU,OAAO,EAEH,OAAO;AAM5E,OAAM,YAJsB,OAAO,OACjC,oBAAoB,sBAAsB,EAAE,CAC7C,CAAC,KAAK,eAAe,WAAW,WAAW,EAEL,OAAO;AAE9C,OAAM,2BAA2B,OAAO;AAExC,WAAU,sBAAsB,EAC9B,WAAW,MACZ,CAAC;AAEF,0BAAyB,OAAO;AAEhC,WAAU,6BAA6B,EACrC,WAAW,MACZ,CAAC;AAIF,YAAW,MAAM,UAAU,OAAO,WAAW,EAAE,EAAE;EAC/C,MAAM,EAAE,sBAAsB,uBAAuB;AAErD,QAAM,OAAO,aAAa;GACxB,cAAc;IACZ;IACA;IACD;GACD,eAAe;GAChB,CAAC"}
|
|
@@ -15,7 +15,8 @@ const handleContentDeclarationFileChange = async (filePath, config) => {
|
|
|
15
15
|
const allDictionariesPaths = await getBuiltDictionariesPath(config);
|
|
16
16
|
const localeDictionaries = await loadLocalDictionaries(filePath, config);
|
|
17
17
|
const dictionariesOutput = await buildDictionary(localeDictionaries, config);
|
|
18
|
-
const
|
|
18
|
+
const updatedDictionaries = Object.values(dictionariesOutput?.mergedDictionaries ?? {});
|
|
19
|
+
const updatedDictionariesPaths = updatedDictionaries.map((dictionary) => dictionary.dictionaryPath);
|
|
19
20
|
const { excludeKeys, hasRebuilt } = await cleanRemovedContentDeclaration(filePath, localeDictionaries.map((dictionary) => dictionary.key), config);
|
|
20
21
|
const hasNewDictionaries = updatedDictionariesPaths.some((updatedDictionaryPath) => !allDictionariesPaths.includes(updatedDictionaryPath));
|
|
21
22
|
if (hasRebuilt || hasNewDictionaries) {
|
|
@@ -23,8 +24,10 @@ const handleContentDeclarationFileChange = async (filePath, config) => {
|
|
|
23
24
|
await createDictionaryEntryPoint(config, { excludeKeys });
|
|
24
25
|
appLogger("Dictionary list built", { isVerbose: true });
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
}
|
|
28
|
+
await createTypes(updatedDictionaries.map((dictionary) => dictionary.dictionary), config);
|
|
29
|
+
appLogger("TypeScript types built", { isVerbose: true });
|
|
30
|
+
if (hasNewDictionaries) {
|
|
28
31
|
await createModuleAugmentation(config);
|
|
29
32
|
appLogger("Module augmentation built", { isVerbose: true });
|
|
30
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleContentDeclarationFileChange.mjs","names":["allDictionariesPaths: string[]"],"sources":["../../src/handleContentDeclarationFileChange.ts"],"sourcesContent":["import { getAppLogger } from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { cleanRemovedContentDeclaration } from './cleanRemovedContentDeclaration';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { getBuiltDictionariesPath } from './createDictionaryEntryPoint/getBuiltDictionariesPath';\nimport { createTypes } from './createType';\nimport { createModuleAugmentation } from './createType/createModuleAugmentation';\nimport { loadLocalDictionaries } from './loadDictionaries/loadLocalDictionaries';\nimport { formatPath } from './utils/formatter';\n\nexport const handleContentDeclarationFileChange = async (\n filePath: string,\n config: IntlayerConfig\n) => {\n const appLogger = getAppLogger(config);\n\n // Process the file with the functionToRun\n appLogger(`Change detected: ${formatPath(filePath)}`, {\n isVerbose: true,\n });\n\n const allDictionariesPaths: string[] = await getBuiltDictionariesPath(config);\n\n const localeDictionaries = await loadLocalDictionaries(filePath, config);\n\n const dictionariesOutput = await buildDictionary(localeDictionaries, config);\n const
|
|
1
|
+
{"version":3,"file":"handleContentDeclarationFileChange.mjs","names":["allDictionariesPaths: string[]"],"sources":["../../src/handleContentDeclarationFileChange.ts"],"sourcesContent":["import { getAppLogger } from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { cleanRemovedContentDeclaration } from './cleanRemovedContentDeclaration';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { getBuiltDictionariesPath } from './createDictionaryEntryPoint/getBuiltDictionariesPath';\nimport { createTypes } from './createType';\nimport { createModuleAugmentation } from './createType/createModuleAugmentation';\nimport { loadLocalDictionaries } from './loadDictionaries/loadLocalDictionaries';\nimport { formatPath } from './utils/formatter';\n\nexport const handleContentDeclarationFileChange = async (\n filePath: string,\n config: IntlayerConfig\n) => {\n const appLogger = getAppLogger(config);\n\n // Process the file with the functionToRun\n appLogger(`Change detected: ${formatPath(filePath)}`, {\n isVerbose: true,\n });\n\n const allDictionariesPaths: string[] = await getBuiltDictionariesPath(config);\n\n const localeDictionaries = await loadLocalDictionaries(filePath, config);\n\n const dictionariesOutput = await buildDictionary(localeDictionaries, config);\n const updatedDictionaries = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n );\n const updatedDictionariesPaths = updatedDictionaries.map(\n (dictionary) => dictionary.dictionaryPath\n );\n\n const { excludeKeys, hasRebuilt } = await cleanRemovedContentDeclaration(\n filePath,\n localeDictionaries.map((dictionary) => dictionary.key),\n config\n );\n\n const hasNewDictionaries = updatedDictionariesPaths.some(\n (updatedDictionaryPath) =>\n !allDictionariesPaths.includes(updatedDictionaryPath)\n );\n\n // Rebuild Entry Point & Module Augmentation\n // These only need to be updated if the *list* of dictionaries changed (Add/Remove/Rename)\n if (hasRebuilt || hasNewDictionaries) {\n // If hasRebuilt is true, cleanRemovedContentDeclaration has already updated the entry point\n // to remove the old keys (and it likely included the new ones if they were already on disk).\n // If NOT hasRebuilt, we explicitly need to update the entry point to include the new dictionaries.\n if (!hasRebuilt) {\n await createDictionaryEntryPoint(config, { excludeKeys });\n appLogger('Dictionary list built', {\n isVerbose: true,\n });\n }\n }\n\n // Rebuild Types\n // Always regenerate types when a file changes, as the content structure (interface) might have changed\n // even if the key is the same.\n const dictionariesToBuild = updatedDictionaries.map(\n (dictionary) => dictionary.dictionary\n );\n\n await createTypes(dictionariesToBuild, config);\n appLogger('TypeScript types built', {\n isVerbose: true,\n });\n\n if (hasNewDictionaries) {\n await createModuleAugmentation(config);\n appLogger('Module augmentation built', {\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 config.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration: config,\n });\n }\n};\n"],"mappings":";;;;;;;;;;;AAWA,MAAa,qCAAqC,OAChD,UACA,WACG;CACH,MAAM,YAAY,aAAa,OAAO;AAGtC,WAAU,oBAAoB,WAAW,SAAS,IAAI,EACpD,WAAW,MACZ,CAAC;CAEF,MAAMA,uBAAiC,MAAM,yBAAyB,OAAO;CAE7E,MAAM,qBAAqB,MAAM,sBAAsB,UAAU,OAAO;CAExE,MAAM,qBAAqB,MAAM,gBAAgB,oBAAoB,OAAO;CAC5E,MAAM,sBAAsB,OAAO,OACjC,oBAAoB,sBAAsB,EAAE,CAC7C;CACD,MAAM,2BAA2B,oBAAoB,KAClD,eAAe,WAAW,eAC5B;CAED,MAAM,EAAE,aAAa,eAAe,MAAM,+BACxC,UACA,mBAAmB,KAAK,eAAe,WAAW,IAAI,EACtD,OACD;CAED,MAAM,qBAAqB,yBAAyB,MACjD,0BACC,CAAC,qBAAqB,SAAS,sBAAsB,CACxD;AAID,KAAI,cAAc,oBAIhB;MAAI,CAAC,YAAY;AACf,SAAM,2BAA2B,QAAQ,EAAE,aAAa,CAAC;AACzD,aAAU,yBAAyB,EACjC,WAAW,MACZ,CAAC;;;AAWN,OAAM,YAJsB,oBAAoB,KAC7C,eAAe,WAAW,WAC5B,EAEsC,OAAO;AAC9C,WAAU,0BAA0B,EAClC,WAAW,MACZ,CAAC;AAEF,KAAI,oBAAoB;AACtB,QAAM,yBAAyB,OAAO;AACtC,YAAU,6BAA6B,EACrC,WAAW,MACZ,CAAC;;AAKJ,YAAW,MAAM,UAAU,OAAO,WAAW,EAAE,EAAE;EAC/C,MAAM,EAAE,sBAAsB,uBAAuB;AAErD,QAAM,OAAO,aAAa;GACxB,cAAc;IACZ;IACA;IACD;GACD,eAAe;GAChB,CAAC"}
|
|
@@ -15,7 +15,7 @@ const handleUnlinkedContentDeclarationFile = async (filePath, config) => {
|
|
|
15
15
|
const localeDictionaries = await loadLocalDictionaries((await listDictionaries(config)).filter((file) => normalize(file) !== normalize(filePath)), config);
|
|
16
16
|
await cleanRemovedContentDeclaration(filePath, [], config);
|
|
17
17
|
const dictionariesOutput = await buildDictionary(localeDictionaries, config);
|
|
18
|
-
await createTypes(Object.values(dictionariesOutput?.mergedDictionaries ?? {}).map((dictionary) => dictionary.
|
|
18
|
+
await createTypes(Object.values(dictionariesOutput?.mergedDictionaries ?? {}).map((dictionary) => dictionary.dictionary), config);
|
|
19
19
|
appLogger("Dictionaries rebuilt", { isVerbose: true });
|
|
20
20
|
await createModuleAugmentation(config);
|
|
21
21
|
appLogger("Module augmentation built", { isVerbose: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleUnlinkedContentDeclarationFile.mjs","names":[],"sources":["../../src/handleUnlinkedContentDeclarationFile.ts"],"sourcesContent":["import { normalize } from 'node:path';\nimport { getAppLogger } from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { cleanRemovedContentDeclaration } from './cleanRemovedContentDeclaration';\nimport { createTypes } from './createType';\nimport { createModuleAugmentation } from './createType/createModuleAugmentation';\nimport { listDictionaries } from './listDictionariesPath';\nimport { loadLocalDictionaries } from './loadDictionaries/loadLocalDictionaries';\nimport { formatPath } from './utils/formatter';\n\nexport const handleUnlinkedContentDeclarationFile = async (\n filePath: string,\n config: IntlayerConfig\n) => {\n const appLogger = getAppLogger(config);\n\n // Process the file with the functionToRun\n appLogger(`Unlinked detected: ${formatPath(filePath)}`, {\n isVerbose: true,\n });\n\n const files: string[] = await listDictionaries(config);\n\n const existingFiles = files.filter(\n (file) => normalize(file) !== normalize(filePath)\n );\n\n const localeDictionaries = await loadLocalDictionaries(existingFiles, config);\n\n await cleanRemovedContentDeclaration(filePath, [], config);\n\n const dictionariesOutput = await buildDictionary(localeDictionaries, config);\n\n const
|
|
1
|
+
{"version":3,"file":"handleUnlinkedContentDeclarationFile.mjs","names":[],"sources":["../../src/handleUnlinkedContentDeclarationFile.ts"],"sourcesContent":["import { normalize } from 'node:path';\nimport { getAppLogger } from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { cleanRemovedContentDeclaration } from './cleanRemovedContentDeclaration';\nimport { createTypes } from './createType';\nimport { createModuleAugmentation } from './createType/createModuleAugmentation';\nimport { listDictionaries } from './listDictionariesPath';\nimport { loadLocalDictionaries } from './loadDictionaries/loadLocalDictionaries';\nimport { formatPath } from './utils/formatter';\n\nexport const handleUnlinkedContentDeclarationFile = async (\n filePath: string,\n config: IntlayerConfig\n) => {\n const appLogger = getAppLogger(config);\n\n // Process the file with the functionToRun\n appLogger(`Unlinked detected: ${formatPath(filePath)}`, {\n isVerbose: true,\n });\n\n const files: string[] = await listDictionaries(config);\n\n const existingFiles = files.filter(\n (file) => normalize(file) !== normalize(filePath)\n );\n\n const localeDictionaries = await loadLocalDictionaries(existingFiles, config);\n\n await cleanRemovedContentDeclaration(filePath, [], config);\n\n const dictionariesOutput = await buildDictionary(localeDictionaries, config);\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, config);\n\n appLogger('Dictionaries rebuilt', {\n isVerbose: true,\n });\n\n await createModuleAugmentation(config);\n\n appLogger('Module augmentation built', {\n isVerbose: true,\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 config.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration: config,\n });\n }\n};\n"],"mappings":";;;;;;;;;;;AAWA,MAAa,uCAAuC,OAClD,UACA,WACG;CACH,MAAM,YAAY,aAAa,OAAO;AAGtC,WAAU,sBAAsB,WAAW,SAAS,IAAI,EACtD,WAAW,MACZ,CAAC;CAQF,MAAM,qBAAqB,MAAM,uBANT,MAAM,iBAAiB,OAAO,EAE1B,QACzB,SAAS,UAAU,KAAK,KAAK,UAAU,SAAS,CAClD,EAEqE,OAAO;AAE7E,OAAM,+BAA+B,UAAU,EAAE,EAAE,OAAO;CAE1D,MAAM,qBAAqB,MAAM,gBAAgB,oBAAoB,OAAO;AAM5E,OAAM,YAJsB,OAAO,OACjC,oBAAoB,sBAAsB,EAAE,CAC7C,CAAC,KAAK,eAAe,WAAW,WAAW,EAEL,OAAO;AAE9C,WAAU,wBAAwB,EAChC,WAAW,MACZ,CAAC;AAEF,OAAM,yBAAyB,OAAO;AAEtC,WAAU,6BAA6B,EACrC,WAAW,MACZ,CAAC;AAIF,YAAW,MAAM,UAAU,OAAO,WAAW,EAAE,EAAE;EAC/C,MAAM,EAAE,sBAAsB,uBAAuB;AAErD,QAAM,OAAO,aAAa;GACxB,cAAc;IACZ;IACA;IACD;GACD,eAAe;GAChB,CAAC"}
|
package/dist/esm/index.mjs
CHANGED
|
@@ -24,6 +24,7 @@ import { handleContentDeclarationFileChange } from "./handleContentDeclarationFi
|
|
|
24
24
|
import { listDictionaries, listDictionariesWithStats } from "./listDictionariesPath.mjs";
|
|
25
25
|
import { handleUnlinkedContentDeclarationFile } from "./handleUnlinkedContentDeclarationFile.mjs";
|
|
26
26
|
import { getContentDeclarationFileTemplate } from "./getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.mjs";
|
|
27
|
+
import { initIntlayer } from "./init/index.mjs";
|
|
27
28
|
import { listGitFiles, listGitLines } from "./listGitFiles.mjs";
|
|
28
29
|
import { sortAlphabetically } from "./utils/sortAlphabetically.mjs";
|
|
29
30
|
import { loadRemoteDictionaries } from "./loadDictionaries/loadRemoteDictionaries.mjs";
|
|
@@ -50,4 +51,4 @@ import { runParallel } from "./utils/runParallel/index.mjs";
|
|
|
50
51
|
import { verifyIdenticObjectFormat } from "./utils/verifyIdenticObjectFormat.mjs";
|
|
51
52
|
import { buildAndWatchIntlayer, watch } from "./watcher.mjs";
|
|
52
53
|
|
|
53
|
-
export { ATTRIBUTES_TO_EXTRACT, assembleJSON, buildAndWatchIntlayer, buildDictionary, buildFilesList, chunkJSON, cleanOutputDir, createDictionaryEntryPoint, createModuleAugmentation, createTypes, detectExportedComponentName, detectFormatCommand, extractDictionaryKey, extractIntlayer, fetchDistantDictionaries, formatDictionaries, formatDictionariesOutput, formatDictionary, formatDictionaryOutput, formatLocale, formatPath, generateDictionaryListContent, generateKey, getBuiltDictionariesPath, getBuiltDynamicDictionariesPath, getBuiltFetchDictionariesPath, getBuiltRemoteDictionariesPath, getBuiltUnmergedDictionariesPath, getChunk, getComponentTransformPattern, getComponentTransformPatternSync, getContentDeclarationFileTemplate, getExtensionFromFormat, getFileHash, getFormatFromExtension, getGlobalLimiter, getTaskLimiter, handleAdditionalContentDeclarationFile, handleContentDeclarationFileChange, handleUnlinkedContentDeclarationFile, isInvalidDictionary, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, loadContentDeclarations, loadDictionaries, loadLocalDictionaries, loadRemoteDictionaries, pLimit, parallelize, parallelizeGlobal, prepareIntlayer, reconstructFromSingleChunk, reduceDictionaryContent, reduceObjectFormat, resolveObjectPromises, runOnce, runParallel, shouldExtract, sortAlphabetically, splitTextByLines, transformFiles, transformJSFile, verifyIdenticObjectFormat, watch, writeContentDeclaration, writeJSFile };
|
|
54
|
+
export { ATTRIBUTES_TO_EXTRACT, assembleJSON, buildAndWatchIntlayer, buildDictionary, buildFilesList, chunkJSON, cleanOutputDir, createDictionaryEntryPoint, createModuleAugmentation, createTypes, detectExportedComponentName, detectFormatCommand, extractDictionaryKey, extractIntlayer, fetchDistantDictionaries, formatDictionaries, formatDictionariesOutput, formatDictionary, formatDictionaryOutput, formatLocale, formatPath, generateDictionaryListContent, generateKey, getBuiltDictionariesPath, getBuiltDynamicDictionariesPath, getBuiltFetchDictionariesPath, getBuiltRemoteDictionariesPath, getBuiltUnmergedDictionariesPath, getChunk, getComponentTransformPattern, getComponentTransformPatternSync, getContentDeclarationFileTemplate, getExtensionFromFormat, getFileHash, getFormatFromExtension, getGlobalLimiter, getTaskLimiter, handleAdditionalContentDeclarationFile, handleContentDeclarationFileChange, handleUnlinkedContentDeclarationFile, initIntlayer, isInvalidDictionary, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, loadContentDeclarations, loadDictionaries, loadLocalDictionaries, loadRemoteDictionaries, pLimit, parallelize, parallelizeGlobal, prepareIntlayer, reconstructFromSingleChunk, reduceDictionaryContent, reduceObjectFormat, resolveObjectPromises, runOnce, runParallel, shouldExtract, sortAlphabetically, splitTextByLines, transformFiles, transformJSFile, verifyIdenticObjectFormat, watch, writeContentDeclaration, writeJSFile };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { initConfig } from "../initConfig/index.mjs";
|
|
2
|
+
import { access, readFile, readdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { ANSIColors, colorize, colorizePath, logger, v, x } from "@intlayer/config";
|
|
5
|
+
|
|
6
|
+
//#region src/init/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* UTILITIES
|
|
9
|
+
*/
|
|
10
|
+
const rootDir = process.cwd();
|
|
11
|
+
const exists = async (filePath) => {
|
|
12
|
+
try {
|
|
13
|
+
await access(join(rootDir, filePath));
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const readFileFromRoot = async (filePath) => await readFile(join(rootDir, filePath), "utf8");
|
|
20
|
+
const writeFileToRoot = async (filePath, content) => await writeFile(join(rootDir, filePath), content, "utf8");
|
|
21
|
+
const parseJSONWithComments = (jsonString) => {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(jsonString);
|
|
24
|
+
} catch {}
|
|
25
|
+
const cleanedLines = jsonString.split("\n").map((line) => {
|
|
26
|
+
let inString = false;
|
|
27
|
+
let result = "";
|
|
28
|
+
for (let i = 0; i < line.length; i++) {
|
|
29
|
+
const char = line[i];
|
|
30
|
+
const nextChar = line[i + 1];
|
|
31
|
+
if (char === "\"" && (i === 0 || line[i - 1] !== "\\")) {
|
|
32
|
+
inString = !inString;
|
|
33
|
+
result += char;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (inString) {
|
|
37
|
+
result += char;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (char === "/" && nextChar === "/") break;
|
|
41
|
+
if (char === "/" && nextChar === "*") {
|
|
42
|
+
const endIndex = line.indexOf("*/", i + 2);
|
|
43
|
+
if (endIndex !== -1) {
|
|
44
|
+
i = endIndex + 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
result += char;
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
});
|
|
52
|
+
return JSON.parse(cleanedLines.join("\n"));
|
|
53
|
+
};
|
|
54
|
+
const findTsConfigFiles = async () => {
|
|
55
|
+
try {
|
|
56
|
+
return (await readdir(rootDir)).filter((file) => file === "tsconfig.json" || /^tsconfig\..+\.json$/.test(file));
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* MAIN LOGIC
|
|
63
|
+
*/
|
|
64
|
+
const initIntlayer = async () => {
|
|
65
|
+
logger(colorize("Checking Intlayer configuration...", ANSIColors.CYAN));
|
|
66
|
+
if (!await exists("package.json")) {
|
|
67
|
+
logger(`${x} No ${colorizePath("package.json")} found. Please run this script from the project root.`, { level: "error" });
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const gitignorePath = ".gitignore";
|
|
71
|
+
if (await exists(gitignorePath)) {
|
|
72
|
+
const gitignoreContent = await readFileFromRoot(gitignorePath);
|
|
73
|
+
if (!gitignoreContent.includes("intlayer")) {
|
|
74
|
+
await writeFileToRoot(gitignorePath, `${gitignoreContent}\n\n# Intlayer\n.intlayer\n`);
|
|
75
|
+
logger(`${v} Added ${colorizePath(".intlayer")} to ${colorizePath(gitignorePath)}`);
|
|
76
|
+
} else logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);
|
|
77
|
+
}
|
|
78
|
+
const tsConfigFiles = await findTsConfigFiles();
|
|
79
|
+
let hasTsConfig = false;
|
|
80
|
+
for (const fileName of tsConfigFiles) if (await exists(fileName)) {
|
|
81
|
+
hasTsConfig = true;
|
|
82
|
+
try {
|
|
83
|
+
const config = parseJSONWithComments(await readFileFromRoot(fileName));
|
|
84
|
+
const typeDefinition = ".intlayer/**/*.ts";
|
|
85
|
+
let updated = false;
|
|
86
|
+
if (!config.include) {} else if (Array.isArray(config.include) && !config.include.some((patten) => patten.includes(".intlayer"))) {
|
|
87
|
+
config.include.push(typeDefinition);
|
|
88
|
+
updated = true;
|
|
89
|
+
} else if (config.include.includes(typeDefinition)) logger(`${v} ${colorizePath(fileName)} already includes intlayer types`);
|
|
90
|
+
if (updated) {
|
|
91
|
+
await writeFileToRoot(fileName, JSON.stringify(config, null, 2));
|
|
92
|
+
logger(`${v} Updated ${colorizePath(fileName)} to include intlayer types`);
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
logger(`${x} Could not parse or update ${colorizePath(fileName)}. You may need to add ${colorizePath(".intlayer/types/**/*.ts")} manually.`, { level: "warn" });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
await initConfig(hasTsConfig ? "intlayer.config.ts" : "intlayer.config.mjs", rootDir);
|
|
99
|
+
for (const file of [
|
|
100
|
+
"vite.config.ts",
|
|
101
|
+
"vite.config.js",
|
|
102
|
+
"vite.config.mjs"
|
|
103
|
+
]) if (await exists(file)) {
|
|
104
|
+
let content = await readFileFromRoot(file);
|
|
105
|
+
if (!content.includes("vite-intlayer")) {
|
|
106
|
+
content = `import { intlayer } from 'vite-intlayer'; // Add the plugin to the Vite plugin list\n${content}`;
|
|
107
|
+
await writeFileToRoot(file, content);
|
|
108
|
+
logger(`${v} Injected import into ${colorizePath(file)}`);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
for (const file of [
|
|
113
|
+
"next.config.js",
|
|
114
|
+
"next.config.mjs",
|
|
115
|
+
"next.config.ts"
|
|
116
|
+
]) if (await exists(file)) {
|
|
117
|
+
let content = await readFileFromRoot(file);
|
|
118
|
+
if (!content.includes("next-intlayer")) {
|
|
119
|
+
content = `import { withIntlayer } from 'next-intlayer'; // Add the plugin to the Next.js configuration\n${content}`;
|
|
120
|
+
await writeFileToRoot(file, content);
|
|
121
|
+
logger(`${v} Injected import into ${colorizePath(file)}`);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
logger(`${v} ${colorize("Intlayer init setup complete.", ANSIColors.GREEN)}`);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
export { initIntlayer };
|
|
130
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/init/index.ts"],"sourcesContent":["import { access, readdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n ANSIColors,\n colorize,\n colorizePath,\n logger,\n v,\n x,\n} from '@intlayer/config';\nimport { initConfig } from '../initConfig';\n\n/**\n * UTILITIES\n */\nconst rootDir = process.cwd();\n\n// Helper to check if a file exists\nconst exists = async (filePath: string) => {\n try {\n await access(join(rootDir, filePath));\n return true;\n } catch {\n return false;\n }\n};\n\n// Helper to read a file\nconst readFileFromRoot = async (filePath: string) =>\n await readFile(join(rootDir, filePath), 'utf8');\n\n// Helper to write a file\nconst writeFileToRoot = async (filePath: string, content: string) =>\n await writeFile(join(rootDir, filePath), content, 'utf8');\n\n// Helper to parse JSON that may contain comments (tsconfig allows comments)\nconst parseJSONWithComments = (jsonString: string) => {\n // First, try parsing as-is (most tsconfig files don't have comments)\n try {\n return JSON.parse(jsonString);\n } catch {\n // If that fails, try stripping comments\n // Note: This simple approach removes comments line by line to avoid\n // matching glob patterns like /* and */ that appear in paths\n }\n\n // Process line by line to safely remove comments\n const lines = jsonString.split('\\n');\n const cleanedLines = lines.map((line) => {\n // Track if we're inside a string\n let inString = false;\n let result = '';\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n const nextChar = line[i + 1];\n\n // Handle string boundaries (accounting for escaped quotes)\n if (char === '\"' && (i === 0 || line[i - 1] !== '\\\\')) {\n inString = !inString;\n result += char;\n continue;\n }\n\n // If we're inside a string, keep the character\n if (inString) {\n result += char;\n continue;\n }\n\n // Check for single-line comment outside of strings\n if (char === '/' && nextChar === '/') {\n // Rest of line is a comment, stop here\n break;\n }\n\n // Check for multi-line comment start (/* ... */)\n // For simplicity, we only handle single-line /* */ comments here\n if (char === '/' && nextChar === '*') {\n const endIndex = line.indexOf('*/', i + 2);\n if (endIndex !== -1) {\n // Skip the comment\n i = endIndex + 1;\n continue;\n }\n }\n\n result += char;\n }\n\n return result;\n });\n\n return JSON.parse(cleanedLines.join('\\n'));\n};\n\n// Helper to find all tsconfig files (tsconfig.json, tsconfig.*.json)\nconst findTsConfigFiles = async (): Promise<string[]> => {\n try {\n const files = await readdir(rootDir);\n\n return files.filter(\n (file) => file === 'tsconfig.json' || /^tsconfig\\..+\\.json$/.test(file)\n );\n } catch {\n return [];\n }\n};\n\n/**\n * MAIN LOGIC\n */\n\nexport const initIntlayer = async () => {\n logger(colorize('Checking Intlayer configuration...', ANSIColors.CYAN));\n\n // Check for package.json to ensure we are in a project root\n if (!(await exists('package.json'))) {\n logger(\n `${x} No ${colorizePath('package.json')} found. Please run this script from the project root.`,\n { level: 'error' }\n );\n process.exit(1);\n }\n\n // Check .gitignore\n const gitignorePath = '.gitignore';\n if (await exists(gitignorePath)) {\n const gitignoreContent = await readFileFromRoot(gitignorePath);\n\n if (!gitignoreContent.includes('intlayer')) {\n const newContent = `${gitignoreContent}\\n\\n# Intlayer\\n.intlayer\\n`;\n await writeFileToRoot(gitignorePath, newContent);\n logger(\n `${v} Added ${colorizePath('.intlayer')} to ${colorizePath(gitignorePath)}`\n );\n } else {\n logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);\n }\n }\n\n // Check TSConfigs\n // Find all tsconfig files (tsconfig.json, tsconfig.*.json)\n const tsConfigFiles = await findTsConfigFiles();\n\n let hasTsConfig = false;\n\n for (const fileName of tsConfigFiles) {\n if (await exists(fileName)) {\n hasTsConfig = true;\n try {\n const fileContent = await readFileFromRoot(fileName);\n const config = parseJSONWithComments(fileContent);\n const typeDefinition = '.intlayer/**/*.ts';\n\n // Check if include array exists - if not, skip (likely a solution-style tsconfig with references)\n let updated = false;\n if (!config.include) {\n // Skip tsconfig files without include array (e.g. solution-style configs with references)\n } else if (\n Array.isArray(config.include) &&\n !(config.include as string[]).some((patten: string) =>\n patten.includes('.intlayer')\n )\n ) {\n config.include.push(typeDefinition);\n updated = true;\n } else if (config.include.includes(typeDefinition)) {\n logger(\n `${v} ${colorizePath(fileName)} already includes intlayer types`\n );\n }\n\n if (updated) {\n // We write back using standard JSON stringify (comments will be lost, sadly)\n // If preserving comments is critical, a more complex parser/printer is needed.\n await writeFileToRoot(fileName, JSON.stringify(config, null, 2));\n logger(\n `${v} Updated ${colorizePath(fileName)} to include intlayer types`\n );\n }\n } catch {\n logger(\n `${x} Could not parse or update ${colorizePath(fileName)}. You may need to add ${colorizePath('.intlayer/types/**/*.ts')} manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // Initialize Intlayer configuration file\n const format = hasTsConfig ? 'intlayer.config.ts' : 'intlayer.config.mjs';\n await initConfig(format, rootDir);\n\n // Check Vite Config\n const viteConfigs = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n\n for (const file of viteConfigs) {\n if (await exists(file)) {\n let content = await readFileFromRoot(file);\n\n if (!content.includes('vite-intlayer')) {\n const viteImport =\n \"import { intlayer } from 'vite-intlayer'; // Add the plugin to the Vite plugin list\";\n\n // Prepend the import\n content = `${viteImport}\\n${content}`;\n await writeFileToRoot(file, content);\n logger(`${v} Injected import into ${colorizePath(file)}`);\n }\n break; // Stop after finding one vite config\n }\n }\n\n // Check Next Config\n const nextConfigs = ['next.config.js', 'next.config.mjs', 'next.config.ts'];\n\n for (const file of nextConfigs) {\n if (await exists(file)) {\n let content = await readFileFromRoot(file);\n\n if (!content.includes('next-intlayer')) {\n const nextImport =\n \"import { withIntlayer } from 'next-intlayer'; // Add the plugin to the Next.js configuration\";\n\n // Prepend the import\n content = `${nextImport}\\n${content}`;\n await writeFileToRoot(file, content);\n logger(`${v} Injected import into ${colorizePath(file)}`);\n }\n break; // Stop after finding one next config\n }\n }\n\n logger(`${v} ${colorize('Intlayer init setup complete.', ANSIColors.GREEN)}`);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, relative } from "node:path";
|
|
3
|
+
import { colorizePath, logger, searchConfigurationFile, v } from "@intlayer/config";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
//#region src/initConfig/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* UTILITIES
|
|
9
|
+
*/
|
|
10
|
+
const rootDir = process.cwd();
|
|
11
|
+
const isESModule = typeof import.meta.url === "string";
|
|
12
|
+
const currentFileDir = isESModule ? dirname(fileURLToPath(import.meta.url)) : __dirname;
|
|
13
|
+
const writeFileToRoot = async (filePath, content) => await writeFile(join(rootDir, filePath), content, "utf8");
|
|
14
|
+
const readTemplate = async (templatePath) => await readFile(join(currentFileDir, "templates", templatePath), "utf8");
|
|
15
|
+
const getTemplatePath = (format) => {
|
|
16
|
+
switch (format) {
|
|
17
|
+
case "ts": return "ts.txt";
|
|
18
|
+
case "cjs": return "cjs.txt";
|
|
19
|
+
case "mjs": return "mjs.txt";
|
|
20
|
+
case "js": return "js.txt";
|
|
21
|
+
case "json": return "json.txt";
|
|
22
|
+
default: return "ts.txt";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the Intlayer configuration file
|
|
27
|
+
*/
|
|
28
|
+
const initConfig = async (format, baseDir) => {
|
|
29
|
+
const { configurationFilePath } = searchConfigurationFile(baseDir);
|
|
30
|
+
if (configurationFilePath) {
|
|
31
|
+
logger(`${v} ${colorizePath(relative(baseDir, configurationFilePath))} already exists`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
await writeFileToRoot(format, await readTemplate(getTemplatePath(format.split(".").pop())));
|
|
35
|
+
logger(`Created ${format}`);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { initConfig, isESModule };
|
|
40
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/initConfig/index.ts"],"sourcesContent":["import { readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n colorizePath,\n type configurationFilesCandidates,\n logger,\n searchConfigurationFile,\n v,\n} from '@intlayer/config';\n\n/**\n * UTILITIES\n */\nconst rootDir = process.cwd();\nexport const isESModule = typeof import.meta.url === 'string';\n\nconst currentFileDir = isESModule\n ? dirname(fileURLToPath(import.meta.url))\n : __dirname;\n\n// Helper to write a file\nconst writeFileToRoot = async (filePath: string, content: string) =>\n await writeFile(join(rootDir, filePath), content, 'utf8');\n\n// Helper to read a template file\nconst readTemplate = async (templatePath: string) =>\n await readFile(join(currentFileDir, 'templates', templatePath), 'utf8');\n\ntype ConfigFormat = 'ts' | 'cjs' | 'mjs' | 'js' | 'json';\n\nconst getTemplatePath = (format: ConfigFormat) => {\n switch (format) {\n case 'ts':\n return 'ts.txt';\n case 'cjs':\n return 'cjs.txt';\n case 'mjs':\n return 'mjs.txt';\n case 'js':\n return 'js.txt';\n case 'json':\n return 'json.txt';\n default:\n return 'ts.txt';\n }\n};\n\n/**\n * Initialize the Intlayer configuration file\n */\nexport const initConfig = async (\n format: (typeof configurationFilesCandidates)[number],\n baseDir: string\n) => {\n // Search for configuration file\n const { configurationFilePath } = searchConfigurationFile(baseDir);\n\n // return if the configuration file is found\n if (configurationFilePath) {\n const relativePath = relative(baseDir, configurationFilePath);\n logger(`${v} ${colorizePath(relativePath)} already exists`);\n return;\n }\n\n // Extract the format from the filename (e.g. 'intlayer.config.ts' -> 'ts')\n const extension = format.split('.').pop() as ConfigFormat;\n\n const templatePath = getTemplatePath(extension);\n const configContent = await readTemplate(templatePath);\n\n await writeFileToRoot(format, configContent);\n logger(`Created ${format}`);\n};\n"],"mappings":";;;;;;;;;AAcA,MAAM,UAAU,QAAQ,KAAK;AAC7B,MAAa,aAAa,OAAO,OAAO,KAAK,QAAQ;AAErD,MAAM,iBAAiB,aACnB,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,GACvC;AAGJ,MAAM,kBAAkB,OAAO,UAAkB,YAC/C,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,SAAS,OAAO;AAG3D,MAAM,eAAe,OAAO,iBAC1B,MAAM,SAAS,KAAK,gBAAgB,aAAa,aAAa,EAAE,OAAO;AAIzE,MAAM,mBAAmB,WAAyB;AAChD,SAAQ,QAAR;EACE,KAAK,KACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK,KACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;;;;AAOb,MAAa,aAAa,OACxB,QACA,YACG;CAEH,MAAM,EAAE,0BAA0B,wBAAwB,QAAQ;AAGlE,KAAI,uBAAuB;AAEzB,SAAO,GAAG,EAAE,GAAG,aADM,SAAS,SAAS,sBAAsB,CACpB,CAAC,iBAAiB;AAC3D;;AASF,OAAM,gBAAgB,QAFA,MAAM,aADP,gBAFH,OAAO,MAAM,IAAI,CAAC,KAAK,CAEM,CACO,CAEV;AAC5C,QAAO,WAAW,SAAS"}
|
|
@@ -97,6 +97,7 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
const pluginDictionaries = await Promise.all(loadPluginDictionariesPromise).then((dictionaries) => dictionaries.flat()).then((dictionaries) => filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => formatDictionaries(dictionaries));
|
|
100
|
+
const pluginDictionariesTime = Date.now();
|
|
100
101
|
const localDictionaries = await loadContentDeclarations(Array.isArray(contentDeclarationsPaths) ? contentDeclarationsPaths : [contentDeclarationsPaths], configuration, setLoadDictionariesStatus).then((dictionaries) => filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => formatDictionaries(dictionaries));
|
|
101
102
|
const localDictionariesTime = Date.now();
|
|
102
103
|
setLoadDictionariesStatus(localDictionaries.map((dictionary) => ({
|
|
@@ -113,7 +114,6 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
113
114
|
onError: (e) => logger$1.setRemoteError(e)
|
|
114
115
|
}).then((dictionaries) => filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => formatDictionaries(dictionaries));
|
|
115
116
|
const remoteDictionariesTime = Date.now();
|
|
116
|
-
const pluginDictionariesTime = Date.now();
|
|
117
117
|
logger$1.finish();
|
|
118
118
|
printSummary(configuration);
|
|
119
119
|
return {
|
|
@@ -121,9 +121,9 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
121
121
|
remoteDictionaries,
|
|
122
122
|
pluginDictionaries,
|
|
123
123
|
time: {
|
|
124
|
-
localDictionaries: localDictionariesTime -
|
|
124
|
+
localDictionaries: localDictionariesTime - pluginDictionariesTime,
|
|
125
125
|
remoteDictionaries: remoteDictionariesTime - localDictionariesTime,
|
|
126
|
-
pluginDictionaries: pluginDictionariesTime -
|
|
126
|
+
pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
};
|