@intlayer/engine 9.3.0 → 9.3.1
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/README.md +24 -24
- package/dist/assets/initConfig/templates/cjs.txt +1 -1
- package/dist/assets/initConfig/templates/mjs.txt +1 -1
- package/dist/assets/initConfig/templates/ts.txt +1 -1
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
- package/dist/cjs/_virtual/_utils_asset.cjs +2 -1
- package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +2 -1
- package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -1
- package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +4 -2
- package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
- package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
- package/dist/cjs/cleanOutputDir.cjs.map +1 -1
- package/dist/cjs/cleanRemovedContentDeclaration.cjs +7 -4
- package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +5 -3
- package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
- package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
- package/dist/cjs/createType/createModuleAugmentation.cjs +2 -1
- package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
- package/dist/cjs/createType/createType.cjs.map +1 -1
- package/dist/cjs/detectFormatCommand.cjs.map +1 -1
- package/dist/cjs/docReview/alignBlocks.cjs +1 -1
- package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
- package/dist/cjs/docReview/computeSimilarity.cjs +0 -1
- package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
- package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +0 -1
- package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
- package/dist/cjs/docReview/normalizeBlock.cjs +0 -1
- package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
- package/dist/cjs/docReview/planActions.cjs +0 -1
- package/dist/cjs/docReview/planActions.cjs.map +1 -1
- package/dist/cjs/docReview/rebuildDocument.cjs +0 -1
- package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
- package/dist/cjs/docReview/reviewReport.cjs +2 -1
- package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
- package/dist/cjs/docReview/segmentDocument.cjs +0 -1
- package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
- package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
- package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
- package/dist/cjs/formatDictionary.cjs.map +1 -1
- package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
- package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +4 -2
- package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
- package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -2
- package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
- package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
- package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +4 -2
- package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
- package/dist/cjs/init/cms.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +1 -3
- package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +2 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +0 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +3 -5
- package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +18 -12
- package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +57 -14
- package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
- package/dist/cjs/init/index.cjs +66 -38
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
- package/dist/cjs/init/utils/fileSystem.cjs +3 -1
- package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
- package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
- package/dist/cjs/init/utils/jsonParser.cjs +0 -1
- package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
- package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
- package/dist/cjs/init/utils/packageManager.cjs +4 -2
- package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
- package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
- package/dist/cjs/init/utils/version.cjs +0 -1
- package/dist/cjs/init/utils/version.cjs.map +1 -1
- package/dist/cjs/initConfig/index.cjs +12 -8
- package/dist/cjs/initConfig/index.cjs.map +1 -1
- package/dist/cjs/installSkills/index.cjs.map +1 -1
- package/dist/cjs/listDictionariesPath.cjs +6 -5
- package/dist/cjs/listDictionariesPath.cjs.map +1 -1
- package/dist/cjs/listGitFiles.cjs.map +1 -1
- package/dist/cjs/listProjects.cjs +2 -1
- package/dist/cjs/listProjects.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +2 -1
- package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +8 -5
- package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +2 -1
- package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/log.cjs +10 -6
- package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
- package/dist/cjs/logConfigDetails.cjs +4 -3
- package/dist/cjs/logConfigDetails.cjs.map +1 -1
- package/dist/cjs/prepareIntlayer.cjs +5 -3
- package/dist/cjs/prepareIntlayer.cjs.map +1 -1
- package/dist/cjs/reduceDictionaryContent/applyMask.cjs +0 -1
- package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
- package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +2 -1
- package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
- package/dist/cjs/scan/calculateScore.cjs +0 -1
- package/dist/cjs/scan/calculateScore.cjs.map +1 -1
- package/dist/cjs/scan/checks.cjs +1 -1
- package/dist/cjs/scan/checks.cjs.map +1 -1
- package/dist/cjs/scan/parseHtml.cjs +0 -1
- package/dist/cjs/scan/parseHtml.cjs.map +1 -1
- package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
- package/dist/cjs/syncPluginKit/createFileAdapter.cjs +2 -1
- package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
- package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +4 -1
- package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
- package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +0 -1
- package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
- package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +0 -1
- package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
- package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
- package/dist/cjs/utils/babelParser.cjs.map +1 -1
- package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
- package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
- package/dist/cjs/utils/chunkArray.cjs +0 -1
- package/dist/cjs/utils/chunkArray.cjs.map +1 -1
- package/dist/cjs/utils/formatter.cjs.map +1 -1
- package/dist/cjs/utils/getContentExtension.cjs +1 -4
- package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
- package/dist/cjs/utils/getFormatFromExtension.cjs +0 -1
- package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
- package/dist/cjs/utils/getPathHash.cjs +0 -1
- package/dist/cjs/utils/getPathHash.cjs.map +1 -1
- package/dist/cjs/utils/mergeChunks.cjs +0 -1
- package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
- package/dist/cjs/utils/pLimit.cjs +0 -1
- package/dist/cjs/utils/pLimit.cjs.map +1 -1
- package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
- package/dist/cjs/utils/reduceObjectFormat.cjs +0 -1
- package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
- package/dist/cjs/utils/resolveObjectPromises.cjs +0 -1
- package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
- package/dist/cjs/utils/resolveRelativePath.cjs +4 -1
- package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
- package/dist/cjs/utils/runOnce.cjs +2 -2
- package/dist/cjs/utils/runOnce.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/bootstrap.cjs +0 -1
- package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
- package/dist/cjs/utils/sortAlphabetically.cjs +0 -1
- package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
- package/dist/cjs/utils/splitTextByLine.cjs +0 -1
- package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
- package/dist/cjs/utils/verifyIdenticObjectFormat.cjs +0 -1
- package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
- package/dist/cjs/watcher.cjs +4 -2
- package/dist/cjs/watcher.cjs.map +1 -1
- package/dist/cjs/writeConfiguration/index.cjs +2 -1
- package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +0 -1
- package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +26 -23
- package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs +6 -5
- package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +9 -3
- package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +2 -1
- package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -1
- package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +4 -2
- package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
- package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
- package/dist/esm/_virtual/_utils_asset.mjs +2 -1
- package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +2 -1
- package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
- package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
- package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +4 -2
- package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
- package/dist/esm/cleanRemovedContentDeclaration.mjs +7 -4
- package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
- package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs +5 -3
- package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
- package/dist/esm/createType/createModuleAugmentation.mjs +2 -1
- package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
- package/dist/esm/docReview/alignBlocks.mjs +1 -1
- package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
- package/dist/esm/docReview/reviewReport.mjs +2 -1
- package/dist/esm/docReview/reviewReport.mjs.map +1 -1
- package/dist/esm/handleAdditionalContentDeclarationFile.mjs +4 -2
- package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
- package/dist/esm/handleContentDeclarationFileChange.mjs +6 -2
- package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
- package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +4 -2
- package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +1 -3
- package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +2 -1
- package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +4 -6
- package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +17 -10
- package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +58 -15
- package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
- package/dist/esm/init/index.mjs +66 -38
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
- package/dist/esm/init/utils/fileSystem.mjs +3 -1
- package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
- package/dist/esm/init/utils/packageManager.mjs +4 -2
- package/dist/esm/init/utils/packageManager.mjs.map +1 -1
- package/dist/esm/initConfig/index.mjs +12 -8
- package/dist/esm/initConfig/index.mjs.map +1 -1
- package/dist/esm/listDictionariesPath.mjs +6 -5
- package/dist/esm/listDictionariesPath.mjs.map +1 -1
- package/dist/esm/listProjects.mjs +2 -1
- package/dist/esm/listProjects.mjs.map +1 -1
- package/dist/esm/loadDictionaries/getIntlayerBundle.mjs +2 -1
- package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +8 -5
- package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs +2 -1
- package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
- package/dist/esm/loadDictionaries/log.mjs +10 -6
- package/dist/esm/loadDictionaries/log.mjs.map +1 -1
- package/dist/esm/logConfigDetails.mjs +4 -3
- package/dist/esm/logConfigDetails.mjs.map +1 -1
- package/dist/esm/prepareIntlayer.mjs +5 -3
- package/dist/esm/prepareIntlayer.mjs.map +1 -1
- package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs +2 -1
- package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
- package/dist/esm/scan/checks.mjs +1 -1
- package/dist/esm/scan/checks.mjs.map +1 -1
- package/dist/esm/syncPluginKit/createFileAdapter.mjs +2 -1
- package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
- package/dist/esm/syncPluginKit/createSyncPlugin.mjs +4 -1
- package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
- package/dist/esm/utils/babelParser.mjs.map +1 -1
- package/dist/esm/utils/getContentExtension.mjs +1 -3
- package/dist/esm/utils/getContentExtension.mjs.map +1 -1
- package/dist/esm/utils/resolveRelativePath.mjs +4 -1
- package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
- package/dist/esm/utils/runOnce.mjs +2 -2
- package/dist/esm/utils/runOnce.mjs.map +1 -1
- package/dist/esm/watcher.mjs +4 -2
- package/dist/esm/watcher.mjs.map +1 -1
- package/dist/esm/writeConfiguration/index.mjs +2 -1
- package/dist/esm/writeConfiguration/index.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/transformJSFile.mjs +26 -23
- package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/transformJSONFile.mjs +6 -5
- package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +9 -3
- package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/writeJSFile.mjs +2 -1
- package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -1
- package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +4 -2
- package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
- package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +9 -4
- package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
- package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +6 -2
- package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
- package/package.json +10 -10
package/dist/cjs/watcher.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.cjs","names":["ANSIColor","prepareIntlayer","formatPath","existsSync","handleContentDeclarationFileMoved","writeContentDeclaration","handleAdditionalContentDeclarationFile","handleContentDeclarationFileChange","handleUnlinkedContentDeclarationFile"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { existsSync, watch as fsWatch } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { basename, dirname, resolve } from 'node:path';\nimport * as ANSIColor from '@intlayer/config/colors';\nimport { transpileTSToCJS } from '@intlayer/config/file';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearDiskCacheMemory,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { formatPath } from './utils';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Array-based sequential task queue — no Promise chain accumulation, no race conditions\nconst taskQueue: (() => Promise<void>)[] = [];\nlet isProcessing = false;\n\nconst processQueue = async () => {\n if (isProcessing) return;\n isProcessing = true;\n while (taskQueue.length > 0) {\n const task = taskQueue.shift()!;\n try {\n await task();\n } catch (error) {\n console.error(error);\n }\n }\n isProcessing = false;\n};\n\nconst processEvent = (task: () => Promise<void>) => {\n taskQueue.push(task);\n processQueue();\n};\n\ntype WatchOptions = {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n persistent?: boolean;\n};\n\n// awaitWriteFinish equivalent: debounce per path until the file is stable\nconst STABILITY_THRESHOLD = 1000;\n\nconst createStabilityDebounce = () => {\n const pending = new Map<string, NodeJS.Timeout>();\n return (path: string, handler: () => void) => {\n const existing = pending.get(path);\n if (existing) clearTimeout(existing);\n pending.set(\n path,\n setTimeout(() => {\n pending.delete(path);\n handler();\n }, STABILITY_THRESHOLD)\n );\n };\n};\n\n// Initialize @parcel/watcher (non-persistent until subscribed)\nexport const watch = async (options?: WatchOptions) => {\n const { subscribe } = await import('@parcel/watcher');\n\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n excludedPath,\n } = configuration.content;\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n if (configuration.build.optimize === true) {\n appLogger(\n [\n `Build optimization is forced to ${colorize('true', ANSIColor.GREY)}, but watching is enabled too.`,\n 'It may lead to dev mode performance degradation as well as import errors.',\n 'Its recommended to keep the',\n colorize('`build.optimized`', ANSIColor.BLUE),\n 'option',\n colorize('undefined', ANSIColor.GREY),\n 'to get the best dev mode experience',\n ],\n {\n level: 'warn',\n }\n );\n }\n\n // Strip glob markers from excludedPath entries to get plain segments (e.g. 'node_modules')\n const excludedSegments = excludedPath.map((segment) =>\n segment.replace(/^\\*\\*\\//, '').replace(/\\/\\*\\*$/, '')\n );\n\n const normalizedConfigPath = configurationFilePath\n ? normalizePath(configurationFilePath)\n : null;\n\n const { mainDir, baseDir } = configuration.system;\n const normalizedMainDir = normalizePath(mainDir);\n const normalizedIntlayerDir = normalizePath(dirname(mainDir));\n\n const subscriptions: { unsubscribe: () => Promise<void> }[] = [];\n\n const scheduleStable = createStabilityDebounce();\n\n // ── mainDir watcher (depth 0) ──────────────────────────────────────────────\n // Detects broken or missing entry-point files inside .intlayer/main\n if (existsSync(mainDir)) {\n const mainDirSub = await subscribe(normalizedMainDir, (err, events) => {\n if (err || isProcessing) return;\n\n for (const event of events) {\n const eventPath = normalizePath(event.path);\n // depth-0 filter: only files directly inside mainDir\n const rel = eventPath.slice(normalizedMainDir.length + 1);\n if (!rel || rel.includes('/')) continue;\n // Temp files written by the bundler (write-then-rename) are build-internal;\n // their deletion must not trigger a clean rebuild.\n if (rel.endsWith('.tmp')) continue;\n\n if (event.type === 'update') {\n processEvent(async () => {\n try {\n // Validate that the regenerated entry point — and the relative\n // dictionary graph it imports — still resolves, by bundling it\n // in-memory with esbuild (via the shared, freshness-checked\n // transpile cache). This replaces a cache-busting dynamic\n // `import()`, which leaked a permanent record into Node's ESM\n // registry on every rebuild since that registry is never evicted.\n const entryCode = await readFile(event.path, 'utf-8');\n await transpileTSToCJS(entryCode, event.path);\n } catch {\n appLogger(\n `Entry point ${basename(event.path)} failed to load, running clean rebuild...`,\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n }\n });\n } else if (event.type === 'delete') {\n processEvent(async () => {\n appLogger(\n [\n 'Entry point',\n formatPath(basename(event.path)),\n 'was removed, running clean rebuild...',\n ],\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n });\n }\n }\n });\n subscriptions.push(mainDirSub);\n }\n\n // ── baseDir watcher (depth 0) — detect .intlayer directory removal ─────────\n // Native fs.watch is non-recursive and ideal for single-directory depth-0 detection.\n const intlayerDirName = basename(normalizedIntlayerDir);\n const fsDirWatcher = fsWatch(\n baseDir,\n { persistent: isWatchMode },\n (eventType, filename) => {\n if (isProcessing || !filename) return;\n if (filename !== intlayerDirName) return;\n\n const fullPath = normalizePath(resolve(baseDir, filename));\n if (fullPath !== normalizedIntlayerDir) return;\n\n if (eventType === 'rename' && !existsSync(normalizedIntlayerDir)) {\n appLogger([\n formatPath('.intlayer'),\n 'directory removed, running clean rebuild...',\n ]);\n processEvent(() =>\n prepareIntlayer(configuration, { clean: true, forceRun: true })\n );\n }\n }\n );\n subscriptions.push({\n unsubscribe: async () => {\n fsDirWatcher.close();\n },\n });\n\n // ── main content watcher ───────────────────────────────────────────────────\n // Ignore patterns for @parcel/watcher (micromatch globs)\n const ignorePatterns = excludedSegments.map((s) => `**/${s}/**`);\n\n // Strip trailing slashes so directory matching stays exact. A user-supplied\n const contentDirs = contentDir\n .map((dir) => normalizePath(dir).replace(/\\/+$/, ''))\n .filter(existsSync);\n\n // Collect unique directories to subscribe to (dirs only, not file paths)\n const dirsToWatch = new Set<string>(contentDirs);\n if (normalizedConfigPath) {\n dirsToWatch.add(normalizePath(dirname(normalizedConfigPath)));\n }\n\n const contentHandler = (\n err: Error | null,\n events: Array<{ type: string; path: string }>\n ) => {\n if (err) {\n appLogger(`Watcher error: ${err}`, { level: 'error' });\n appLogger('Restarting watcher');\n prepareIntlayer(configuration);\n return;\n }\n\n for (const event of events) {\n const filePath = event.path;\n const path = normalizePath(filePath);\n\n const isConfigFile =\n normalizedConfigPath && path === normalizedConfigPath;\n\n if (!isConfigFile) {\n // Must originate from a watched content directory\n const isInContentDir = contentDirs.some(\n (d) => path.startsWith(`${d}/`) || path === d\n );\n if (!isInContentDir) continue;\n\n if (excludedSegments.some((segment) => path.includes(`/${segment}`)))\n continue;\n\n if (!fileExtensions.some((extension) => path.endsWith(extension)))\n continue;\n }\n\n if (event.type === 'create') {\n const fileName = basename(filePath);\n\n // Move detection must happen synchronously before any debounce\n let isMove = false;\n let matchedOldPath: string | undefined;\n\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n if (isMove && matchedOldPath) {\n processEvent(async () => {\n await handleContentDeclarationFileMoved(\n matchedOldPath!,\n filePath,\n configuration\n );\n });\n } else {\n // Debounce: wait for write to finish before reading the file\n scheduleStable(path, () => {\n processEvent(async () => {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n { key: name, content: {}, filePath },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(\n filePath,\n configuration\n );\n });\n });\n }\n } else if (event.type === 'update') {\n scheduleStable(path, () => {\n processEvent(async () => {\n if (isConfigFile) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(filePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n // Evict in-memory caches so loadContentDeclaration picks up fresh content\n clearAllCache();\n clearDiskCacheMemory();\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n });\n });\n } else if (event.type === 'delete') {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'create' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n }\n }\n };\n\n for (const dir of dirsToWatch) {\n const sub = await subscribe(dir, contentHandler, {\n ignore: ignorePatterns,\n });\n\n subscriptions.push(sub);\n }\n\n return subscriptions;\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n // Only enter watch mode when the caller explicitly opts in via `persistent`.\n // `configuration.content.watch` is the dev-mode signal consumed by bundler\n // plugins (e.g. vite-intlayer's `configureServer`); it must not coerce\n // `intlayer build` (which passes `persistent: false`) into a persistent\n // watcher, since that prevents the build command from ever exiting.\n if (options?.persistent) {\n await watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"watcher.cjs","names":["getConfigurationAndFilePath","getAppLogger","colorize","ANSIColor","normalizePath","dirname","existsSync","readFile","transpileTSToCJS","basename","prepareIntlayer","formatPath","fsWatch","resolve","handleContentDeclarationFileMoved","writeContentDeclaration","handleAdditionalContentDeclarationFile","handleContentDeclarationFileChange","handleUnlinkedContentDeclarationFile","getConfiguration"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { existsSync, watch as fsWatch } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { basename, dirname, resolve } from 'node:path';\nimport * as ANSIColor from '@intlayer/config/colors';\nimport { transpileTSToCJS } from '@intlayer/config/file';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearDiskCacheMemory,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { formatPath } from './utils';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Array-based sequential task queue — no Promise chain accumulation, no race conditions\nconst taskQueue: (() => Promise<void>)[] = [];\nlet isProcessing = false;\n\nconst processQueue = async () => {\n if (isProcessing) return;\n isProcessing = true;\n while (taskQueue.length > 0) {\n const task = taskQueue.shift()!;\n try {\n await task();\n } catch (error) {\n console.error(error);\n }\n }\n isProcessing = false;\n};\n\nconst processEvent = (task: () => Promise<void>) => {\n taskQueue.push(task);\n processQueue();\n};\n\ntype WatchOptions = {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n persistent?: boolean;\n};\n\n// awaitWriteFinish equivalent: debounce per path until the file is stable\nconst STABILITY_THRESHOLD = 1000;\n\nconst createStabilityDebounce = () => {\n const pending = new Map<string, NodeJS.Timeout>();\n return (path: string, handler: () => void) => {\n const existing = pending.get(path);\n if (existing) clearTimeout(existing);\n pending.set(\n path,\n setTimeout(() => {\n pending.delete(path);\n handler();\n }, STABILITY_THRESHOLD)\n );\n };\n};\n\n// Initialize @parcel/watcher (non-persistent until subscribed)\nexport const watch = async (options?: WatchOptions) => {\n const { subscribe } = await import('@parcel/watcher');\n\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n excludedPath,\n } = configuration.content;\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n if (configuration.build.optimize === true) {\n appLogger(\n [\n `Build optimization is forced to ${colorize('true', ANSIColor.GREY)}, but watching is enabled too.`,\n 'It may lead to dev mode performance degradation as well as import errors.',\n 'Its recommended to keep the',\n colorize('`build.optimized`', ANSIColor.BLUE),\n 'option',\n colorize('undefined', ANSIColor.GREY),\n 'to get the best dev mode experience',\n ],\n {\n level: 'warn',\n }\n );\n }\n\n // Strip glob markers from excludedPath entries to get plain segments (e.g. 'node_modules')\n const excludedSegments = excludedPath.map((segment) =>\n segment.replace(/^\\*\\*\\//, '').replace(/\\/\\*\\*$/, '')\n );\n\n const normalizedConfigPath = configurationFilePath\n ? normalizePath(configurationFilePath)\n : null;\n\n const { mainDir, baseDir } = configuration.system;\n const normalizedMainDir = normalizePath(mainDir);\n const normalizedIntlayerDir = normalizePath(dirname(mainDir));\n\n const subscriptions: { unsubscribe: () => Promise<void> }[] = [];\n\n const scheduleStable = createStabilityDebounce();\n\n // ── mainDir watcher (depth 0) ──────────────────────────────────────────────\n // Detects broken or missing entry-point files inside .intlayer/main\n if (existsSync(mainDir)) {\n const mainDirSub = await subscribe(normalizedMainDir, (err, events) => {\n if (err || isProcessing) return;\n\n for (const event of events) {\n const eventPath = normalizePath(event.path);\n // depth-0 filter: only files directly inside mainDir\n const rel = eventPath.slice(normalizedMainDir.length + 1);\n if (!rel || rel.includes('/')) continue;\n // Temp files written by the bundler (write-then-rename) are build-internal;\n // their deletion must not trigger a clean rebuild.\n if (rel.endsWith('.tmp')) continue;\n\n if (event.type === 'update') {\n processEvent(async () => {\n try {\n // Validate that the regenerated entry point — and the relative\n // dictionary graph it imports — still resolves, by bundling it\n // in-memory with esbuild (via the shared, freshness-checked\n // transpile cache). This replaces a cache-busting dynamic\n // `import()`, which leaked a permanent record into Node's ESM\n // registry on every rebuild since that registry is never evicted.\n const entryCode = await readFile(event.path, 'utf-8');\n await transpileTSToCJS(entryCode, event.path);\n } catch {\n appLogger(\n `Entry point ${basename(event.path)} failed to load, running clean rebuild...`,\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n }\n });\n } else if (event.type === 'delete') {\n processEvent(async () => {\n appLogger(\n [\n 'Entry point',\n formatPath(basename(event.path)),\n 'was removed, running clean rebuild...',\n ],\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n });\n }\n }\n });\n subscriptions.push(mainDirSub);\n }\n\n // ── baseDir watcher (depth 0) — detect .intlayer directory removal ─────────\n // Native fs.watch is non-recursive and ideal for single-directory depth-0 detection.\n const intlayerDirName = basename(normalizedIntlayerDir);\n const fsDirWatcher = fsWatch(\n baseDir,\n { persistent: isWatchMode },\n (eventType, filename) => {\n if (isProcessing || !filename) return;\n if (filename !== intlayerDirName) return;\n\n const fullPath = normalizePath(resolve(baseDir, filename));\n if (fullPath !== normalizedIntlayerDir) return;\n\n if (eventType === 'rename' && !existsSync(normalizedIntlayerDir)) {\n appLogger([\n formatPath('.intlayer'),\n 'directory removed, running clean rebuild...',\n ]);\n processEvent(() =>\n prepareIntlayer(configuration, { clean: true, forceRun: true })\n );\n }\n }\n );\n subscriptions.push({\n unsubscribe: async () => {\n fsDirWatcher.close();\n },\n });\n\n // ── main content watcher ───────────────────────────────────────────────────\n // Ignore patterns for @parcel/watcher (micromatch globs)\n const ignorePatterns = excludedSegments.map((s) => `**/${s}/**`);\n\n // Strip trailing slashes so directory matching stays exact. A user-supplied\n const contentDirs = contentDir\n .map((dir) => normalizePath(dir).replace(/\\/+$/, ''))\n .filter(existsSync);\n\n // Collect unique directories to subscribe to (dirs only, not file paths)\n const dirsToWatch = new Set<string>(contentDirs);\n if (normalizedConfigPath) {\n dirsToWatch.add(normalizePath(dirname(normalizedConfigPath)));\n }\n\n const contentHandler = (\n err: Error | null,\n events: Array<{ type: string; path: string }>\n ) => {\n if (err) {\n appLogger(`Watcher error: ${err}`, { level: 'error' });\n appLogger('Restarting watcher');\n prepareIntlayer(configuration);\n return;\n }\n\n for (const event of events) {\n const filePath = event.path;\n const path = normalizePath(filePath);\n\n const isConfigFile =\n normalizedConfigPath && path === normalizedConfigPath;\n\n if (!isConfigFile) {\n // Must originate from a watched content directory\n const isInContentDir = contentDirs.some(\n (d) => path.startsWith(`${d}/`) || path === d\n );\n if (!isInContentDir) continue;\n\n if (excludedSegments.some((segment) => path.includes(`/${segment}`)))\n continue;\n\n if (!fileExtensions.some((extension) => path.endsWith(extension)))\n continue;\n }\n\n if (event.type === 'create') {\n const fileName = basename(filePath);\n\n // Move detection must happen synchronously before any debounce\n let isMove = false;\n let matchedOldPath: string | undefined;\n\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n if (isMove && matchedOldPath) {\n processEvent(async () => {\n await handleContentDeclarationFileMoved(\n matchedOldPath!,\n filePath,\n configuration\n );\n });\n } else {\n // Debounce: wait for write to finish before reading the file\n scheduleStable(path, () => {\n processEvent(async () => {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n { key: name, content: {}, filePath },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(\n filePath,\n configuration\n );\n });\n });\n }\n } else if (event.type === 'update') {\n scheduleStable(path, () => {\n processEvent(async () => {\n if (isConfigFile) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(filePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n // Evict in-memory caches so loadContentDeclaration picks up fresh content\n clearAllCache();\n clearDiskCacheMemory();\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n });\n });\n } else if (event.type === 'delete') {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'create' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n }\n }\n };\n\n for (const dir of dirsToWatch) {\n const sub = await subscribe(dir, contentHandler, {\n ignore: ignorePatterns,\n });\n\n subscriptions.push(sub);\n }\n\n return subscriptions;\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n // Only enter watch mode when the caller explicitly opts in via `persistent`.\n // `configuration.content.watch` is the dev-mode signal consumed by bundler\n // plugins (e.g. vite-intlayer's `configureServer`); it must not coerce\n // `intlayer build` (which passes `persistent: false`) into a persistent\n // watcher, since that prevents the build command from ever exiting.\n if (options?.persistent) {\n await watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
|
|
@@ -7,7 +7,8 @@ let node_path = require("node:path");
|
|
|
7
7
|
//#region src/writeConfiguration/index.ts
|
|
8
8
|
const isCachedConfigurationUpToDate = async (configuration) => {
|
|
9
9
|
try {
|
|
10
|
-
|
|
10
|
+
const mjsPath = (0, node_path.join)(configuration.system.configDir, "configuration.mjs");
|
|
11
|
+
return await (0, node_fs_promises.readFile)(mjsPath, "utf8") === require_writeConfiguration_generateConfigurationContent.generateConfigurationContent(configuration, "esm");
|
|
11
12
|
} catch {
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["generateConfigurationContent","writeFileIfChanged"],"sources":["../../../src/writeConfiguration/index.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { generateConfigurationContent } from './generateConfigurationContent';\n\nexport const isCachedConfigurationUpToDate = async (\n configuration: IntlayerConfig\n): Promise<boolean | null> => {\n try {\n const mjsPath = join(configuration.system.configDir, 'configuration.mjs');\n const existingContent = await readFile(mjsPath, 'utf8');\n const expectedContent = generateConfigurationContent(configuration, 'esm');\n return existingContent === expectedContent;\n } catch {\n return null; // Can crash if file doesn't exist yet or config is not defined\n }\n};\n\nexport const writeConfiguration = async (configuration: IntlayerConfig) => {\n const { configDir } = configuration.system;\n\n await mkdir(configDir, { recursive: true });\n\n await Promise.all([\n writeFileIfChanged(\n join(configDir, 'configuration.mjs'),\n generateConfigurationContent(configuration, 'esm')\n ),\n writeFileIfChanged(\n join(configDir, 'configuration.cjs'),\n generateConfigurationContent(configuration, 'cjs')\n ),\n ]);\n};\n"],"mappings":";;;;;;;AAMA,MAAa,gCAAgC,OAC3C,kBAC4B;CAC5B,IAAI;
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["join","readFile","generateConfigurationContent","mkdir","writeFileIfChanged"],"sources":["../../../src/writeConfiguration/index.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { generateConfigurationContent } from './generateConfigurationContent';\n\nexport const isCachedConfigurationUpToDate = async (\n configuration: IntlayerConfig\n): Promise<boolean | null> => {\n try {\n const mjsPath = join(configuration.system.configDir, 'configuration.mjs');\n const existingContent = await readFile(mjsPath, 'utf8');\n const expectedContent = generateConfigurationContent(configuration, 'esm');\n return existingContent === expectedContent;\n } catch {\n return null; // Can crash if file doesn't exist yet or config is not defined\n }\n};\n\nexport const writeConfiguration = async (configuration: IntlayerConfig) => {\n const { configDir } = configuration.system;\n\n await mkdir(configDir, { recursive: true });\n\n await Promise.all([\n writeFileIfChanged(\n join(configDir, 'configuration.mjs'),\n generateConfigurationContent(configuration, 'esm')\n ),\n writeFileIfChanged(\n join(configDir, 'configuration.cjs'),\n generateConfigurationContent(configuration, 'cjs')\n ),\n ]);\n};\n"],"mappings":";;;;;;;AAMA,MAAa,gCAAgC,OAC3C,kBAC4B;CAC5B,IAAI;EACF,MAAM,cAAUA,gBAAK,cAAc,OAAO,WAAW,mBAAmB;EAGxE,OAAO,UAFuBC,2BAAS,SAAS,MAAM,MAC9BC,qFAA6B,eAAe,KAC3B;CAC3C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,qBAAqB,OAAO,kBAAkC;CACzE,MAAM,EAAE,cAAc,cAAc;CAEpC,UAAMC,wBAAM,WAAW,EAAE,WAAW,KAAK,CAAC;CAE1C,MAAM,QAAQ,IAAI,CAChBC,kDACEJ,gBAAK,WAAW,mBAAmB,GACnCE,qFAA6B,eAAe,KAAK,CACnD,GACAE,kDACEJ,gBAAK,WAAW,mBAAmB,GACnCE,qFAA6B,eAAe,KAAK,CACnD,CACF,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectExportedComponentName.cjs","names":[],"sources":["../../../src/writeContentDeclaration/detectExportedComponentName.ts"],"sourcesContent":["/**\n * Attempt to detect an exported React component name in the file text.\n * Looks for patterns like:\n * - export const MyComponent = ...\n * - export function MyComponent(...)\n * - export default function MyComponent(...)\n */\nexport const detectExportedComponentName = (\n fileText: string\n): string | null => {\n // Added regexes for default ESM, default CJS, and named exports\n const defaultEsmFnRegex = /export\\s+default\\s+function\\s+(\\w+)/;\n const defaultEsmVarRegex = /export\\s+default\\s+(\\w+)/;\n const cjsDefaultRegex = /module\\.exports\\s*=\\s*(\\w+)/;\n const cjsDefaultVarRegex = /exports\\.default\\s*=\\s*(\\w+)/;\n const namedExportRegex = /export\\s+(?:const|function)\\s+(\\w+)/g;\n\n // Check for default ESM function or variable\n const defaultEsmFnMatch = fileText.match(defaultEsmFnRegex);\n if (defaultEsmFnMatch) {\n return defaultEsmFnMatch[1];\n }\n\n const defaultEsmVarMatch = fileText.match(defaultEsmVarRegex);\n if (defaultEsmVarMatch) {\n return defaultEsmVarMatch[1];\n }\n\n // Check for default CJS\n const cjsDefaultMatch =\n fileText.match(cjsDefaultRegex) || fileText.match(cjsDefaultVarRegex);\n\n if (cjsDefaultMatch) return cjsDefaultMatch[1];\n\n // Otherwise, look for capitalized named exports\n for (const match of fileText.matchAll(namedExportRegex)) {\n if (/^[A-Z]/.test(match[1])) return match[1];\n }\n\n // If we can’t find it, return null\n return null;\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"detectExportedComponentName.cjs","names":[],"sources":["../../../src/writeContentDeclaration/detectExportedComponentName.ts"],"sourcesContent":["/**\n * Attempt to detect an exported React component name in the file text.\n * Looks for patterns like:\n * - export const MyComponent = ...\n * - export function MyComponent(...)\n * - export default function MyComponent(...)\n */\nexport const detectExportedComponentName = (\n fileText: string\n): string | null => {\n // Added regexes for default ESM, default CJS, and named exports\n const defaultEsmFnRegex = /export\\s+default\\s+function\\s+(\\w+)/;\n const defaultEsmVarRegex = /export\\s+default\\s+(\\w+)/;\n const cjsDefaultRegex = /module\\.exports\\s*=\\s*(\\w+)/;\n const cjsDefaultVarRegex = /exports\\.default\\s*=\\s*(\\w+)/;\n const namedExportRegex = /export\\s+(?:const|function)\\s+(\\w+)/g;\n\n // Check for default ESM function or variable\n const defaultEsmFnMatch = fileText.match(defaultEsmFnRegex);\n if (defaultEsmFnMatch) {\n return defaultEsmFnMatch[1];\n }\n\n const defaultEsmVarMatch = fileText.match(defaultEsmVarRegex);\n if (defaultEsmVarMatch) {\n return defaultEsmVarMatch[1];\n }\n\n // Check for default CJS\n const cjsDefaultMatch =\n fileText.match(cjsDefaultRegex) || fileText.match(cjsDefaultVarRegex);\n\n if (cjsDefaultMatch) return cjsDefaultMatch[1];\n\n // Otherwise, look for capitalized named exports\n for (const match of fileText.matchAll(namedExportRegex)) {\n if (/^[A-Z]/.test(match[1])) return match[1];\n }\n\n // If we can’t find it, return null\n return null;\n};\n"],"mappings":";;;;;;;;;AAOA,MAAa,+BACX,aACkB;CAElB,MAAM,oBAAoB;CAC1B,MAAM,qBAAqB;CAC3B,MAAM,kBAAkB;CACxB,MAAM,qBAAqB;CAC3B,MAAM,mBAAmB;CAGzB,MAAM,oBAAoB,SAAS,MAAM,iBAAiB;CAC1D,IAAI,mBACF,OAAO,kBAAkB;CAG3B,MAAM,qBAAqB,SAAS,MAAM,kBAAkB;CAC5D,IAAI,oBACF,OAAO,mBAAmB;CAI5B,MAAM,kBACJ,SAAS,MAAM,eAAe,KAAK,SAAS,MAAM,kBAAkB;CAEtE,IAAI,iBAAiB,OAAO,gBAAgB;CAG5C,KAAK,MAAM,SAAS,SAAS,SAAS,gBAAgB,GACpD,IAAI,SAAS,KAAK,MAAM,EAAE,GAAG,OAAO,MAAM;CAI5C,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processContentDeclarationContent.cjs","names":["NodeTypes","x"],"sources":["../../../src/writeContentDeclaration/processContentDeclarationContent.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { colorizePath, x } from '@intlayer/config/logger';\nimport { deepTransformNode, type Plugins } from '@intlayer/core/interpreter';\nimport type {\n FileContent,\n FileContentConstructor,\n HTMLContent,\n HTMLContentConstructor,\n InsertionContent,\n InsertionContentConstructor,\n MarkdownContent,\n MarkdownContentConstructor,\n} from '@intlayer/core/transpiler';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Write file plugin\n */\n\nconst writeFilePlugin: Plugins = {\n id: 'write-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent) => {\n const fileContent = node.content;\n const filePath = node.fixedPath;\n\n if (typeof fileContent !== 'string') {\n throw new Error('File content must be a string');\n }\n\n if (typeof filePath !== 'string') {\n throw new Error('File path must be a string');\n }\n\n // Write the file to the file system\n try {\n const absoluteFilePath = join(process.cwd(), filePath);\n\n // Create the file directory if it doesn't exist\n const fileDirectory = dirname(absoluteFilePath);\n\n if (!existsSync(fileDirectory)) {\n mkdirSync(fileDirectory, { recursive: true });\n }\n\n // Write the file\n writeFileSync(absoluteFilePath, fileContent);\n } catch (error) {\n throw new Error(\n `${x} Error writing file to ${colorizePath(filePath)}: ${error}`\n );\n }\n\n const transformedFileContent: FileContentConstructor = {\n nodeType: NodeTypes.FILE,\n [NodeTypes.FILE]: node[NodeTypes.FILE],\n };\n\n return transformedFileContent;\n },\n};\n\n/**\n * Markdown file plugin\n */\n\nconst markdownFilePlugin: Plugins = {\n id: 'markdown-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.MARKDOWN,\n transform: (node: MarkdownContent, props, deepTransformNode) => {\n const simplifiedMarkdownNode: MarkdownContentConstructor = {\n nodeType: NodeTypes.MARKDOWN,\n [NodeTypes.MARKDOWN]: deepTransformNode(node[NodeTypes.MARKDOWN], props),\n };\n\n return simplifiedMarkdownNode;\n },\n};\n\n/**\n * Insertion file plugin\n */\n\nconst insertionFilePlugin: Plugins = {\n id: 'insertion-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const simplifiedInsertionNode: InsertionContentConstructor = {\n nodeType: NodeTypes.INSERTION,\n [NodeTypes.INSERTION]: deepTransformNode(\n node[NodeTypes.INSERTION],\n props\n ),\n };\n\n return simplifiedInsertionNode;\n },\n};\n\n/**\n * HTML file plugin\n */\n\nconst htmlFilePlugin: Plugins = {\n id: 'html-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.HTML,\n transform: (node: HTMLContent, props, deepTransformNode) => {\n const simplifiedHTMLNode: HTMLContentConstructor = {\n nodeType: NodeTypes.HTML,\n [NodeTypes.HTML]: deepTransformNode(node[NodeTypes.HTML], props),\n };\n\n return simplifiedHTMLNode;\n },\n};\n\n/**\n * Process content declaration content\n *\n * It filter node that are autogenerated by intlayer to do not rewrite them in the content declaration file.\n *\n * And write external sources as file content if necessary.\n */\nexport const processContentDeclarationContent = async (\n dictionary: Dictionary\n) =>\n deepTransformNode(dictionary, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [\n writeFilePlugin,\n markdownFilePlugin,\n insertionFilePlugin,\n htmlFilePlugin,\n ],\n });\n"],"mappings":";;;;;;;;;;;;;AAqBA,MAAM,kBAA2B;CAC/B,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,SAAsB;EAChC,MAAM,cAAc,KAAK;EACzB,MAAM,WAAW,KAAK;EAEtB,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MAAM,+BAA+B;EAGjD,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,MAAM,4BAA4B;EAI9C,IAAI;GACF,MAAM,
|
|
1
|
+
{"version":3,"file":"processContentDeclarationContent.cjs","names":["NodeTypes","join","dirname","existsSync","x","colorizePath","deepTransformNode"],"sources":["../../../src/writeContentDeclaration/processContentDeclarationContent.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { colorizePath, x } from '@intlayer/config/logger';\nimport { deepTransformNode, type Plugins } from '@intlayer/core/interpreter';\nimport type {\n FileContent,\n FileContentConstructor,\n HTMLContent,\n HTMLContentConstructor,\n InsertionContent,\n InsertionContentConstructor,\n MarkdownContent,\n MarkdownContentConstructor,\n} from '@intlayer/core/transpiler';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Write file plugin\n */\n\nconst writeFilePlugin: Plugins = {\n id: 'write-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent) => {\n const fileContent = node.content;\n const filePath = node.fixedPath;\n\n if (typeof fileContent !== 'string') {\n throw new Error('File content must be a string');\n }\n\n if (typeof filePath !== 'string') {\n throw new Error('File path must be a string');\n }\n\n // Write the file to the file system\n try {\n const absoluteFilePath = join(process.cwd(), filePath);\n\n // Create the file directory if it doesn't exist\n const fileDirectory = dirname(absoluteFilePath);\n\n if (!existsSync(fileDirectory)) {\n mkdirSync(fileDirectory, { recursive: true });\n }\n\n // Write the file\n writeFileSync(absoluteFilePath, fileContent);\n } catch (error) {\n throw new Error(\n `${x} Error writing file to ${colorizePath(filePath)}: ${error}`\n );\n }\n\n const transformedFileContent: FileContentConstructor = {\n nodeType: NodeTypes.FILE,\n [NodeTypes.FILE]: node[NodeTypes.FILE],\n };\n\n return transformedFileContent;\n },\n};\n\n/**\n * Markdown file plugin\n */\n\nconst markdownFilePlugin: Plugins = {\n id: 'markdown-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.MARKDOWN,\n transform: (node: MarkdownContent, props, deepTransformNode) => {\n const simplifiedMarkdownNode: MarkdownContentConstructor = {\n nodeType: NodeTypes.MARKDOWN,\n [NodeTypes.MARKDOWN]: deepTransformNode(node[NodeTypes.MARKDOWN], props),\n };\n\n return simplifiedMarkdownNode;\n },\n};\n\n/**\n * Insertion file plugin\n */\n\nconst insertionFilePlugin: Plugins = {\n id: 'insertion-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const simplifiedInsertionNode: InsertionContentConstructor = {\n nodeType: NodeTypes.INSERTION,\n [NodeTypes.INSERTION]: deepTransformNode(\n node[NodeTypes.INSERTION],\n props\n ),\n };\n\n return simplifiedInsertionNode;\n },\n};\n\n/**\n * HTML file plugin\n */\n\nconst htmlFilePlugin: Plugins = {\n id: 'html-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.HTML,\n transform: (node: HTMLContent, props, deepTransformNode) => {\n const simplifiedHTMLNode: HTMLContentConstructor = {\n nodeType: NodeTypes.HTML,\n [NodeTypes.HTML]: deepTransformNode(node[NodeTypes.HTML], props),\n };\n\n return simplifiedHTMLNode;\n },\n};\n\n/**\n * Process content declaration content\n *\n * It filter node that are autogenerated by intlayer to do not rewrite them in the content declaration file.\n *\n * And write external sources as file content if necessary.\n */\nexport const processContentDeclarationContent = async (\n dictionary: Dictionary\n) =>\n deepTransformNode(dictionary, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [\n writeFilePlugin,\n markdownFilePlugin,\n insertionFilePlugin,\n htmlFilePlugin,\n ],\n });\n"],"mappings":";;;;;;;;;;;;;AAqBA,MAAM,kBAA2B;CAC/B,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,SAAsB;EAChC,MAAM,cAAc,KAAK;EACzB,MAAM,WAAW,KAAK;EAEtB,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MAAM,+BAA+B;EAGjD,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,MAAM,4BAA4B;EAI9C,IAAI;GACF,MAAM,uBAAmBC,gBAAK,QAAQ,IAAI,GAAG,QAAQ;GAGrD,MAAM,oBAAgBC,mBAAQ,gBAAgB;GAE9C,IAAI,KAACC,oBAAW,aAAa,GAC3B,uBAAU,eAAe,EAAE,WAAW,KAAK,CAAC;GAI9C,2BAAc,kBAAkB,WAAW;EAC7C,SAAS,OAAO;GACd,MAAM,IAAI,MACR,GAAGC,0BAAE,6BAAyBC,sCAAa,QAAQ,EAAE,IAAI,OAC3D;EACF;EAOA,OAAO;GAJL,UAAUL,yBAAU;IACnBA,yBAAU,OAAO,KAAKA,yBAAU;EAGP;CAC9B;AACF;;;;AAMA,MAAM,qBAA8B;CAClC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAuB,OAAO,sBAAsB;EAM9D,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,WAAW,kBAAkB,KAAKA,yBAAU,WAAW,KAAK;EAG7C;CAC9B;AACF;;;;AAMA,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAS/D,OAAO;GAPL,UAAUA,yBAAU;IACnBA,yBAAU,YAAY,kBACrB,KAAKA,yBAAU,YACf,KACF;EAG2B;CAC/B;AACF;;;;AAMA,MAAM,iBAA0B;CAC9B,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAmB,OAAO,sBAAsB;EAM1D,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,OAAO,kBAAkB,KAAKA,yBAAU,OAAO,KAAK;EAGzC;CAC1B;AACF;;;;;;;;AASA,MAAa,mCAAmC,OAC9C,mBAEAM,8CAAkB,YAAY;CAC5B,eAAe,WAAW;CAC1B,SAAS,CAAC;CACV,SAAS;EACP;EACA;EACA;EACA;CACF;AACF,CAAC"}
|
|
@@ -240,19 +240,21 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
|
|
|
240
240
|
}, true)], []);
|
|
241
241
|
return b.literal(val);
|
|
242
242
|
}
|
|
243
|
-
if (Array.isArray(val))
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
243
|
+
if (Array.isArray(val)) {
|
|
244
|
+
if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {
|
|
245
|
+
const elements = [...unwrappedExisting.elements];
|
|
246
|
+
val.forEach((item, i) => {
|
|
247
|
+
const elementNode = buildNodeForValue(item, elements[i], fallbackLocale, requiredImports);
|
|
248
|
+
elements[i] = elementNode === SKIP_WRITE ? elements[i] ?? b.literal(null) : elementNode;
|
|
249
|
+
});
|
|
250
|
+
if (elements.length > val.length) elements.length = val.length;
|
|
251
|
+
unwrappedExisting.elements = elements;
|
|
252
|
+
return existingNode;
|
|
253
|
+
} else return b.arrayExpression(val.map((item) => {
|
|
254
|
+
const elementNode = buildNodeForValue(item, null, fallbackLocale, requiredImports);
|
|
255
|
+
return elementNode === SKIP_WRITE ? b.literal(null) : elementNode;
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
256
258
|
const nodeType = val && typeof val === "object" && !Array.isArray(val) ? (0, _intlayer_core_dictionaryManipulator.getNodeType)(val) : null;
|
|
257
259
|
if (nodeType) {
|
|
258
260
|
const strategy = nodeTypeStrategies[nodeType];
|
|
@@ -353,17 +355,18 @@ const addImports = (ast, requiredImports, isESM) => {
|
|
|
353
355
|
});
|
|
354
356
|
const missingCore = Array.from(requiredImports).filter((imp) => !existingCoreImports.has(imp));
|
|
355
357
|
if (missingCore.length === 0) return;
|
|
356
|
-
if (isESM)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
358
|
+
if (isESM) {
|
|
359
|
+
if (coreImportPath) {
|
|
360
|
+
missingCore.forEach((imp) => {
|
|
361
|
+
coreImportPath.node.specifiers.push(b.importSpecifier(b.identifier(imp)));
|
|
362
|
+
});
|
|
363
|
+
coreImportPath.node.specifiers.sort((a, b) => a.imported.name.localeCompare(b.imported.name));
|
|
364
|
+
} else {
|
|
365
|
+
const specifiers = missingCore.sort().map((imp) => b.importSpecifier(b.identifier(imp)));
|
|
366
|
+
const newImport = b.importDeclaration(specifiers, b.literal("intlayer"));
|
|
367
|
+
ast.program.body.unshift(newImport);
|
|
368
|
+
}
|
|
361
369
|
} else {
|
|
362
|
-
const specifiers = missingCore.sort().map((imp) => b.importSpecifier(b.identifier(imp)));
|
|
363
|
-
const newImport = b.importDeclaration(specifiers, b.literal("intlayer"));
|
|
364
|
-
ast.program.body.unshift(newImport);
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
370
|
let insertIndex = 0;
|
|
368
371
|
if (ast.program.body.length > 0 && n.ExpressionStatement.check(ast.program.body[0]) && n.Literal.check(ast.program.body[0].expression)) insertIndex = 1;
|
|
369
372
|
const cjsLines = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformJSFile.cjs","names":["NodeTypes","babelTsParser"],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"sourcesContent":["import { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport * as recast from 'recast';\nimport { babelTsParser } from '../utils/babelParser';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Name of an `intlayer` helper function a node type is printed as.\n *\n * Mirrors the transpiler helpers re-exported by the `intlayer` package\n * (`@intlayer/core/transpiler`).\n */\ntype HelperName =\n | 't'\n | 'enu'\n | 'plural'\n | 'cond'\n | 'gender'\n | 'select'\n | 'insert'\n | 'md'\n | 'html'\n | 'file'\n | 'nest';\n\n/**\n * How a {@link NodeType} is materialized back into source code.\n *\n * - `helperRecord` — printed as `helper({ … })`. The node data is a record of\n * variants (locales, plural categories, conditions, cases…) whose values are\n * rebuilt recursively and merged into the existing object literal.\n * - `helperValue` — printed as `helper(value)`. The node data is a single\n * content, itself possibly another node (e.g. `md(t({ … }))`).\n * - `nesting` — printed as `nest(dictionaryKey, path?)`.\n * - `unwrap` — not a source-level helper: the wrapped value replaces the node,\n * so `{ nodeType: 'text', text: 'Hello' }` is printed as `\"Hello\"`.\n * - `preserve` — framework elements have no data representation, so the\n * existing source expression is kept untouched and nothing is written when\n * there is none.\n * - `structural` — plain objects, arrays and unrecognized nodes, rebuilt by the\n * generic object/array branches.\n */\ntype NodeTypeStrategy =\n | {\n kind: 'helperRecord';\n helper: HelperName;\n /**\n * Extra arguments appended after the record argument, rebuilt from the\n * node attributes (e.g. the variable name carried by a `select` node).\n */\n getExtraArguments?: (\n node: Record<string, unknown>\n ) => recast.types.namedTypes.Literal[];\n }\n | { kind: 'helperValue'; helper: HelperName }\n | { kind: 'nesting'; helper: HelperName }\n | { kind: 'unwrap' }\n | { kind: 'preserve' }\n | { kind: 'structural' };\n\n/**\n * Every {@link NodeType} and how it is written back to a JS/TS declaration file.\n *\n * Typed as `Record<NodeType, NodeTypeStrategy>` so that adding a node type to\n * `@intlayer/types` without registering it here becomes a compile-time error —\n * the same guarantee `getNodeType` gives on the read side.\n */\nconst nodeTypeStrategies: Record<NodeType, NodeTypeStrategy> = {\n [NodeTypes.TRANSLATION]: { kind: 'helperRecord', helper: 't' },\n [NodeTypes.ENUMERATION]: { kind: 'helperRecord', helper: 'enu' },\n [NodeTypes.PLURAL]: { kind: 'helperRecord', helper: 'plural' },\n [NodeTypes.CONDITION]: { kind: 'helperRecord', helper: 'cond' },\n [NodeTypes.GENDER]: { kind: 'helperRecord', helper: 'gender' },\n [NodeTypes.SELECT]: {\n kind: 'helperRecord',\n helper: 'select',\n getExtraArguments: (node) =>\n typeof node.variable === 'string' && node.variable.length > 0\n ? [b.literal(node.variable)]\n : [],\n },\n [NodeTypes.INSERTION]: { kind: 'helperValue', helper: 'insert' },\n [NodeTypes.MARKDOWN]: { kind: 'helperValue', helper: 'md' },\n [NodeTypes.HTML]: { kind: 'helperValue', helper: 'html' },\n [NodeTypes.FILE]: { kind: 'helperValue', helper: 'file' },\n [NodeTypes.NESTED]: { kind: 'nesting', helper: 'nest' },\n [NodeTypes.TEXT]: { kind: 'unwrap' },\n [NodeTypes.NUMBER]: { kind: 'unwrap' },\n [NodeTypes.BOOLEAN]: { kind: 'unwrap' },\n [NodeTypes.NULL]: { kind: 'unwrap' },\n [NodeTypes.REACT_NODE]: { kind: 'preserve' },\n [NodeTypes.PREACT_NODE]: { kind: 'preserve' },\n [NodeTypes.SOLID_NODE]: { kind: 'preserve' },\n [NodeTypes.OBJECT]: { kind: 'structural' },\n [NodeTypes.ARRAY]: { kind: 'structural' },\n [NodeTypes.UNKNOWN]: { kind: 'structural' },\n};\n\n/** Every `intlayer` helper the transform is allowed to rewrite. */\nconst helperNames = new Set<string>(\n Object.values(nodeTypeStrategies).flatMap((strategy) =>\n 'helper' in strategy ? [strategy.helper] : []\n )\n);\n\n/** Helpers wrapping a single content, e.g. `md(t({ … }))`. */\nconst wrapperHelperNames = new Set<string>(\n Object.values(nodeTypeStrategies).flatMap((strategy) =>\n strategy.kind === 'helperValue' ? [strategy.helper] : []\n )\n);\n\n/**\n * Returned by {@link buildNodeForValue} when a value must not be written to the\n * source file — framework elements and functions have no data representation,\n * so the original expression (when there is one) is left untouched and no new\n * property is created otherwise.\n */\nconst SKIP_WRITE = Symbol('intlayer.skipWrite');\n\n/**\n * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).\n * Uses string fallbacks to bypass outdated ast-types definitions.\n */\nconst unwrap = (node: any) => {\n while (\n node &&\n (n.TSSatisfiesExpression?.check(node) ||\n n.TSAsExpression?.check(node) ||\n n.TSTypeAssertion?.check(node) ||\n n.TSNonNullExpression?.check(node) ||\n [\n 'TSSatisfiesExpression',\n 'TSAsExpression',\n 'TSTypeAssertion',\n 'TSNonNullExpression',\n ].includes(node.type))\n ) {\n node = node.expression;\n }\n return node;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n\n return false;\n });\n};\n\n/**\n * Synchronizes numeric suffixes across locales.\n * E.g. \"Hello 1\" -> \"Hello 3\" updates \"Bonjour 1\" to \"Bonjour 3\".\n */\nconst syncNumericSuffixAcrossLocales = (\n existingNode: any,\n fallbackLocaleCode: string,\n newFallbackValue: string\n) => {\n const trailingNumberMatch = newFallbackValue.match(/\\d+(?!.*\\d)/);\n if (!trailingNumberMatch) return;\n const newTrailingNumber = trailingNumberMatch[0];\n\n if (n.ObjectExpression.check(existingNode)) {\n for (const prop of existingNode.properties) {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (\n n.Literal.check(prop.key) &&\n typeof prop.key.value === 'string'\n )\n propName = prop.key.value;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n\n if (propName && propName !== fallbackLocaleCode) {\n if (\n n.Literal.check(prop.value) &&\n typeof prop.value.value === 'string'\n ) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.literal(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n } else if (n.StringLiteral.check(prop.value)) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.stringLiteral(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n }\n }\n }\n }\n }\n};\n\n/**\n * Checks if a value represents a multilingual Intlayer node.\n *\n * A node is multilingual if it is a Translation node, if it wraps one\n * (Markdown, HTML, Insertion…), or if any of its variants contains one\n * (Enumeration, Plural, Condition, Gender, Select…).\n */\nconst isMultilingualNode = (val: any): boolean => {\n if (typeof val !== 'object' || val === null || Array.isArray(val)) {\n return false;\n }\n\n const nodeType = getNodeType(val as ContentNode);\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n const strategy = nodeTypeStrategies[nodeType];\n const nodeData = (val as any)[nodeType];\n\n if (strategy.kind === 'helperValue' || strategy.kind === 'unwrap') {\n return isMultilingualNode(nodeData);\n }\n\n if (\n strategy.kind === 'helperRecord' &&\n nodeData &&\n typeof nodeData === 'object'\n ) {\n return Object.values(nodeData).some((variant) =>\n isMultilingualNode(variant)\n );\n }\n\n return false;\n};\n\n/**\n * Checks whether two AST nodes are literals holding the same value.\n */\nconst isEquivalentLiteral = (left: any, right: any): boolean => {\n const isLiteral = (node: any) =>\n n.Literal.check(node) ||\n n.StringLiteral.check(node) ||\n n.NumericLiteral.check(node) ||\n n.BooleanLiteral.check(node);\n\n return isLiteral(left) && isLiteral(right) && left.value === right.value;\n};\n\n/**\n * Aligns the arguments of an existing call expression with the desired ones.\n *\n * Mutates the call only when the arguments actually differ, so Recast keeps the\n * original formatting (and quote style) of calls that did not change.\n */\nconst syncCallArguments = (callNode: any, desiredArguments: any[]) => {\n const isUnchanged =\n callNode.arguments.length === desiredArguments.length &&\n desiredArguments.every((desired, index) => {\n const current = callNode.arguments[index];\n\n return current === desired || isEquivalentLiteral(current, desired);\n });\n\n if (!isUnchanged) {\n callNode.arguments = desiredArguments;\n }\n};\n\n/**\n * Recursively builds or updates an AST node for a given dictionary value.\n *\n * Returns {@link SKIP_WRITE} when the value cannot be represented in source and\n * no existing expression can be kept.\n */\nconst buildNodeForValue = (\n val: any,\n existingNode: any,\n fallbackLocale: string | undefined, // In per-locale mode, this is the locale of the file\n requiredImports: Set<string>\n): any => {\n // Values with no source representation must never overwrite existing code.\n if (val === undefined || typeof val === 'function') {\n return existingNode ?? SKIP_WRITE;\n }\n\n const unwrappedExisting = unwrap(existingNode);\n\n // --- CRITICAL GUARD: STRICT AST PRESERVATION ---\n // If the existing node is code (JSX, Variables, standard functions), leave it alone.\n // Only allow updates to literals, plain objects, arrays, and Intlayer helpers.\n if (unwrappedExisting) {\n const isUpdatableNode =\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting) ||\n n.NumericLiteral.check(unwrappedExisting) ||\n n.BooleanLiteral.check(unwrappedExisting) ||\n n.TemplateLiteral.check(unwrappedExisting) ||\n n.ObjectExpression.check(unwrappedExisting) ||\n n.ArrayExpression.check(unwrappedExisting) ||\n (n.CallExpression.check(unwrappedExisting) &&\n n.Identifier.check(unwrappedExisting.callee) &&\n helperNames.has(unwrappedExisting.callee.name));\n\n if (!isUpdatableNode) {\n return existingNode;\n }\n }\n\n // If we are in per-locale mode (fallbackLocale is set)\n // and the value is not already a complex translation node,\n // we want to store it as a simple literal, NOT wrapped in t().\n if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n }\n\n if (fallbackLocale && existingNode && !isMultilingualNode(val)) {\n if (\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 't'\n ) {\n const arg = unwrap(existingNode.arguments[0]);\n\n if (n.ObjectExpression.check(arg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(arg, fallbackLocale, val);\n }\n updateObjectLiteral(\n arg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n\n if (!fallbackLocale) {\n requiredImports.add('t');\n }\n\n return existingNode;\n }\n }\n\n // Wrapped translations — `md(t({ … }))`, `html(t({ … }))`, `insert(t({ … }))`:\n // update the inner translation in place instead of replacing the wrapper.\n if (\n (!val || typeof val !== 'object') &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n wrapperHelperNames.has(existingNode.callee.name)\n ) {\n const wrapperName = existingNode.callee.name;\n const innerArg = existingNode.arguments[0];\n\n if (\n n.CallExpression.check(innerArg) &&\n n.Identifier.check(innerArg.callee) &&\n innerArg.callee.name === 't'\n ) {\n const tArg = unwrap(innerArg.arguments[0]);\n\n if (n.ObjectExpression.check(tArg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);\n }\n updateObjectLiteral(\n tArg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n requiredImports.add(wrapperName);\n requiredImports.add('t');\n\n return existingNode;\n }\n }\n }\n }\n\n // 1. Primitives\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (unwrappedExisting) {\n // Preserve existing template literals (backticks)\n if (\n n.TemplateLiteral.check(unwrappedExisting) &&\n unwrappedExisting.quasis[0] &&\n unwrappedExisting.expressions.length === 0\n ) {\n unwrappedExisting.quasis[0].value.raw = String(val);\n unwrappedExisting.quasis[0].value.cooked = String(val);\n return existingNode;\n }\n // Preserve existing standard literals (keeps quote styling)\n if (\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting)\n ) {\n unwrappedExisting.value = val;\n return existingNode;\n }\n }\n\n // Force multiline strings to use Template Literals\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n\n // 2. Arrays\n if (Array.isArray(val)) {\n if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {\n const elements = [...unwrappedExisting.elements];\n val.forEach((item, i) => {\n const elementNode = buildNodeForValue(\n item,\n elements[i],\n fallbackLocale,\n requiredImports\n );\n\n elements[i] =\n elementNode === SKIP_WRITE\n ? (elements[i] ?? b.literal(null))\n : elementNode;\n });\n\n if (elements.length > val.length) elements.length = val.length;\n unwrappedExisting.elements = elements as any;\n\n return existingNode;\n } else {\n return b.arrayExpression(\n val.map((item) => {\n const elementNode = buildNodeForValue(\n item,\n null,\n fallbackLocale,\n requiredImports\n );\n\n return elementNode === SKIP_WRITE ? b.literal(null) : elementNode;\n })\n );\n }\n }\n\n // 3. Intlayer Specialized Nodes — dispatched through the exhaustive registry\n const nodeType =\n val && typeof val === 'object' && !Array.isArray(val)\n ? getNodeType(val as ContentNode)\n : null;\n\n if (nodeType) {\n const strategy = nodeTypeStrategies[nodeType];\n\n // Framework elements (React/Preact/Solid) cannot be serialized back to\n // source: keep whatever the file already declares.\n if (strategy.kind === 'preserve') {\n return existingNode ?? SKIP_WRITE;\n }\n\n const hasNodeData = Object.hasOwn(val as object, nodeType);\n const nodeData = (val as any)[nodeType];\n\n // A typed node missing its payload is malformed — fall back to the generic\n // object branch rather than printing a broken helper call.\n if (strategy.kind !== 'structural' && hasNodeData) {\n if (strategy.kind === 'unwrap') {\n return buildNodeForValue(\n nodeData,\n existingNode,\n fallbackLocale,\n requiredImports\n );\n }\n\n const { helper } = strategy;\n\n requiredImports.add(helper);\n\n const isMatchingCall =\n existingNode &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === helper;\n\n if (strategy.kind === 'helperRecord') {\n const recordArgument =\n isMatchingCall &&\n existingNode.arguments.length > 0 &&\n n.ObjectExpression.check(existingNode.arguments[0])\n ? existingNode.arguments[0]\n : b.objectExpression([]);\n\n updateObjectLiteral(\n recordArgument,\n nodeData ?? {},\n fallbackLocale,\n requiredImports\n );\n\n const callArguments = [\n recordArgument,\n ...(strategy.getExtraArguments?.(val as Record<string, unknown>) ??\n []),\n ];\n\n if (isMatchingCall) {\n syncCallArguments(existingNode, callArguments);\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(helper), callArguments);\n }\n\n if (strategy.kind === 'helperValue') {\n const contentArgument = buildNodeForValue(\n nodeData,\n isMatchingCall && existingNode.arguments.length > 0\n ? existingNode.arguments[0]\n : null,\n fallbackLocale,\n requiredImports\n );\n\n if (contentArgument === SKIP_WRITE) {\n return existingNode ?? SKIP_WRITE;\n }\n\n if (isMatchingCall) {\n // Keep any extra argument the source declares (custom components\n // passed to `md()` / `html()`), which the node does not carry back.\n syncCallArguments(existingNode, [\n contentArgument,\n ...existingNode.arguments.slice(1),\n ]);\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(helper), [contentArgument]);\n }\n\n // strategy.kind === 'nesting'\n const callArguments = [b.literal(nodeData?.dictionaryKey ?? '')];\n\n if (nodeData?.path) callArguments.push(b.literal(nodeData.path));\n\n if (isMatchingCall) {\n syncCallArguments(existingNode, callArguments);\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(helper), callArguments);\n }\n }\n\n // 4. Plain Object\n const objNode =\n unwrappedExisting && n.ObjectExpression.check(unwrappedExisting)\n ? unwrappedExisting\n : b.objectExpression([]);\n\n updateObjectLiteral(objNode, val, fallbackLocale, requiredImports);\n\n return existingNode && unwrappedExisting === existingNode\n ? objNode\n : existingNode || objNode;\n};\n\n/**\n * Recursively updates the AST object literal properties.\n */\nconst updateObjectLiteral = (\n node: recast.types.namedTypes.ObjectExpression,\n data: Record<string, any>,\n fallbackLocale: string | undefined,\n requiredImports: Set<string>\n) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) continue;\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp) {\n const valueNode = buildNodeForValue(\n val,\n existingProp.value,\n fallbackLocale,\n requiredImports\n );\n\n if (valueNode !== SKIP_WRITE) {\n existingProp.value = valueNode;\n }\n } else {\n const isValidId = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);\n const keyNode = isValidId ? b.identifier(key) : b.literal(key);\n const valueNode = buildNodeForValue(\n val,\n null,\n fallbackLocale,\n requiredImports\n );\n\n if (valueNode === SKIP_WRITE) continue;\n\n node.properties.push(b.property('init', keyNode, valueNode));\n }\n }\n};\n\n/**\n * Modifies the AST's top-level imports to inject dynamically needed helper utilities seamlessly.\n */\nconst addImports = (ast: any, requiredImports: Set<string>, isESM: boolean) => {\n if (requiredImports.size === 0) return;\n\n const existingCoreImports = new Set<string>();\n let coreImportPath: any = null;\n\n recast.visit(ast, {\n visitImportDeclaration(path) {\n const source = path.node.source.value;\n\n if (source === 'intlayer') {\n coreImportPath = path;\n path.node.specifiers?.forEach((spec) => {\n if (\n n.ImportSpecifier.check(spec) &&\n typeof spec.imported.name === 'string'\n ) {\n existingCoreImports.add(spec.imported.name);\n }\n });\n }\n\n return false;\n },\n visitVariableDeclaration(path) {\n path.node.declarations.forEach((decl) => {\n if (\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require'\n ) {\n const arg = decl.init.arguments[0];\n\n if (n.Literal.check(arg)) {\n if (arg.value === 'intlayer') {\n if (n.ObjectPattern.check(decl.id)) {\n decl.id.properties.forEach((prop) => {\n if (\n n.Property.check(prop) &&\n (n.Identifier.check(prop.key) ||\n n.Identifier.check(prop.value))\n ) {\n const name = n.Identifier.check(prop.key)\n ? prop.key.name\n : (prop.value as any).name;\n existingCoreImports.add(name);\n }\n });\n } else if (n.Identifier.check(decl.id)) {\n // Handle const intlayer = require('intlayer')\n existingCoreImports.add(decl.id.name);\n }\n }\n }\n }\n });\n\n return false;\n },\n });\n\n const missingCore = Array.from(requiredImports).filter(\n (imp) => !existingCoreImports.has(imp)\n );\n\n if (missingCore.length === 0) return;\n\n if (isESM) {\n if (coreImportPath) {\n missingCore.forEach((imp) => {\n coreImportPath.node.specifiers.push(\n b.importSpecifier(b.identifier(imp))\n );\n });\n coreImportPath.node.specifiers.sort((a: any, b: any) =>\n a.imported.name.localeCompare(b.imported.name)\n );\n } else {\n const specifiers = missingCore\n .sort()\n .map((imp) => b.importSpecifier(b.identifier(imp)));\n const newImport = b.importDeclaration(specifiers, b.literal('intlayer'));\n ast.program.body.unshift(newImport);\n }\n } else {\n let insertIndex = 0;\n\n if (\n ast.program.body.length > 0 &&\n n.ExpressionStatement.check(ast.program.body[0]) &&\n n.Literal.check(ast.program.body[0].expression)\n ) {\n insertIndex = 1; // Insert after 'use strict'\n }\n const cjsLines: any[] = [];\n\n const properties = missingCore.sort().map((imp) => {\n const prop = b.property('init', b.identifier(imp), b.identifier(imp));\n prop.shorthand = true;\n\n return prop;\n });\n cjsLines.push(\n b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern(properties),\n b.callExpression(b.identifier('require'), [b.literal('intlayer')])\n ),\n ])\n );\n\n ast.program.body.splice(insertIndex, 0, ...cjsLines);\n }\n};\n\n/**\n * Updates a JS/TS file seamlessly to map new localization keys, arrays, complex nodes and nested dictionaries gracefully using AST updates via Recast parser.\n */\nexport const transformJSFile = async (\n fileContent: string,\n dictionary: Dictionary,\n fallbackLocale?: Locale,\n noMetadata?: boolean\n): Promise<string> => {\n if (!dictionary || typeof dictionary !== 'object') return fileContent;\n\n let ast: any;\n try {\n ast = recast.parse(fileContent, {\n parser: babelTsParser,\n });\n } catch (error) {\n console.error({ error });\n return fileContent;\n }\n\n let rootObject: any = null;\n let isESM = false;\n\n recast.visit(ast, {\n visitExportDefaultDeclaration() {\n isESM = true;\n\n return false;\n },\n visitImportDeclaration() {\n isESM = true;\n\n return false;\n },\n });\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n const unwrappedDecl = unwrap(decl);\n\n if (n.ObjectExpression.check(unwrappedDecl)) {\n rootObject = unwrappedDecl;\n } else if (n.Identifier.check(unwrappedDecl)) {\n const varName = unwrappedDecl.name;\n recast.visit(ast, {\n visitVariableDeclarator(vp) {\n const unwrappedInit = unwrap(vp.node.init);\n\n if (\n n.Identifier.check(vp.node.id) &&\n vp.node.id.name === varName &&\n n.ObjectExpression.check(unwrappedInit)\n ) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n return false;\n },\n visitAssignmentExpression(path) {\n const left = path.node.left;\n\n if (n.MemberExpression.check(left)) {\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'module' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'exports'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'exports' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'default'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n }\n this.traverse(path);\n },\n });\n\n if (!rootObject) {\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const unwrappedInit = unwrap(path.node.init);\n\n if (!rootObject && n.ObjectExpression.check(unwrappedInit)) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n if (!rootObject) return fileContent;\n\n const requiredImports = new Set<string>();\n const effectiveFallbackLocale = (fallbackLocale as string) ?? 'en';\n\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n ];\n\n if (noMetadata) {\n // Remove key, content and metadata properties if they exist\n rootObject.properties = rootObject.properties.filter((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n return !['key', 'content', ...metadataProperties].includes(propName);\n }\n return true;\n });\n\n // Update satisfies type if exists\n recast.visit(ast, {\n visitNode(path) {\n const node = path.node;\n if (\n (n.TSSatisfiesExpression?.check(node) ||\n node.type === 'TSSatisfiesExpression') &&\n (node as any).typeAnnotation &&\n n.TSTypeReference.check((node as any).typeAnnotation) &&\n n.Identifier.check((node as any).typeAnnotation.typeName) &&\n (node as any).typeAnnotation.typeName.name === 'Dictionary'\n ) {\n (node as any).typeAnnotation = b.tsIndexedAccessType(\n b.tsTypeReference(b.identifier('Dictionary')),\n b.tsLiteralType(b.stringLiteral('content'))\n );\n }\n this.traverse(path);\n },\n });\n } else {\n for (const prop of metadataProperties) {\n if ((dictionary as any)[prop] !== undefined) {\n updateObjectLiteral(\n rootObject,\n { [prop]: (dictionary as any)[prop] },\n undefined,\n requiredImports\n );\n }\n }\n }\n\n if (dictionary.content !== undefined) {\n updateObjectLiteral(\n rootObject,\n noMetadata\n ? (dictionary.content as Record<string, any>)\n : { content: dictionary.content },\n effectiveFallbackLocale,\n requiredImports\n );\n }\n\n addImports(ast, requiredImports, isESM);\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transformJSFile.cjs","names":["NodeTypes","getNodeType","babelTsParser"],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"sourcesContent":["import { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport * as recast from 'recast';\nimport { babelTsParser } from '../utils/babelParser';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Name of an `intlayer` helper function a node type is printed as.\n *\n * Mirrors the transpiler helpers re-exported by the `intlayer` package\n * (`@intlayer/core/transpiler`).\n */\ntype HelperName =\n | 't'\n | 'enu'\n | 'plural'\n | 'cond'\n | 'gender'\n | 'select'\n | 'insert'\n | 'md'\n | 'html'\n | 'file'\n | 'nest';\n\n/**\n * How a {@link NodeType} is materialized back into source code.\n *\n * - `helperRecord` — printed as `helper({ … })`. The node data is a record of\n * variants (locales, plural categories, conditions, cases…) whose values are\n * rebuilt recursively and merged into the existing object literal.\n * - `helperValue` — printed as `helper(value)`. The node data is a single\n * content, itself possibly another node (e.g. `md(t({ … }))`).\n * - `nesting` — printed as `nest(dictionaryKey, path?)`.\n * - `unwrap` — not a source-level helper: the wrapped value replaces the node,\n * so `{ nodeType: 'text', text: 'Hello' }` is printed as `\"Hello\"`.\n * - `preserve` — framework elements have no data representation, so the\n * existing source expression is kept untouched and nothing is written when\n * there is none.\n * - `structural` — plain objects, arrays and unrecognized nodes, rebuilt by the\n * generic object/array branches.\n */\ntype NodeTypeStrategy =\n | {\n kind: 'helperRecord';\n helper: HelperName;\n /**\n * Extra arguments appended after the record argument, rebuilt from the\n * node attributes (e.g. the variable name carried by a `select` node).\n */\n getExtraArguments?: (\n node: Record<string, unknown>\n ) => recast.types.namedTypes.Literal[];\n }\n | { kind: 'helperValue'; helper: HelperName }\n | { kind: 'nesting'; helper: HelperName }\n | { kind: 'unwrap' }\n | { kind: 'preserve' }\n | { kind: 'structural' };\n\n/**\n * Every {@link NodeType} and how it is written back to a JS/TS declaration file.\n *\n * Typed as `Record<NodeType, NodeTypeStrategy>` so that adding a node type to\n * `@intlayer/types` without registering it here becomes a compile-time error —\n * the same guarantee `getNodeType` gives on the read side.\n */\nconst nodeTypeStrategies: Record<NodeType, NodeTypeStrategy> = {\n [NodeTypes.TRANSLATION]: { kind: 'helperRecord', helper: 't' },\n [NodeTypes.ENUMERATION]: { kind: 'helperRecord', helper: 'enu' },\n [NodeTypes.PLURAL]: { kind: 'helperRecord', helper: 'plural' },\n [NodeTypes.CONDITION]: { kind: 'helperRecord', helper: 'cond' },\n [NodeTypes.GENDER]: { kind: 'helperRecord', helper: 'gender' },\n [NodeTypes.SELECT]: {\n kind: 'helperRecord',\n helper: 'select',\n getExtraArguments: (node) =>\n typeof node.variable === 'string' && node.variable.length > 0\n ? [b.literal(node.variable)]\n : [],\n },\n [NodeTypes.INSERTION]: { kind: 'helperValue', helper: 'insert' },\n [NodeTypes.MARKDOWN]: { kind: 'helperValue', helper: 'md' },\n [NodeTypes.HTML]: { kind: 'helperValue', helper: 'html' },\n [NodeTypes.FILE]: { kind: 'helperValue', helper: 'file' },\n [NodeTypes.NESTED]: { kind: 'nesting', helper: 'nest' },\n [NodeTypes.TEXT]: { kind: 'unwrap' },\n [NodeTypes.NUMBER]: { kind: 'unwrap' },\n [NodeTypes.BOOLEAN]: { kind: 'unwrap' },\n [NodeTypes.NULL]: { kind: 'unwrap' },\n [NodeTypes.REACT_NODE]: { kind: 'preserve' },\n [NodeTypes.PREACT_NODE]: { kind: 'preserve' },\n [NodeTypes.SOLID_NODE]: { kind: 'preserve' },\n [NodeTypes.OBJECT]: { kind: 'structural' },\n [NodeTypes.ARRAY]: { kind: 'structural' },\n [NodeTypes.UNKNOWN]: { kind: 'structural' },\n};\n\n/** Every `intlayer` helper the transform is allowed to rewrite. */\nconst helperNames = new Set<string>(\n Object.values(nodeTypeStrategies).flatMap((strategy) =>\n 'helper' in strategy ? [strategy.helper] : []\n )\n);\n\n/** Helpers wrapping a single content, e.g. `md(t({ … }))`. */\nconst wrapperHelperNames = new Set<string>(\n Object.values(nodeTypeStrategies).flatMap((strategy) =>\n strategy.kind === 'helperValue' ? [strategy.helper] : []\n )\n);\n\n/**\n * Returned by {@link buildNodeForValue} when a value must not be written to the\n * source file — framework elements and functions have no data representation,\n * so the original expression (when there is one) is left untouched and no new\n * property is created otherwise.\n */\nconst SKIP_WRITE = Symbol('intlayer.skipWrite');\n\n/**\n * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).\n * Uses string fallbacks to bypass outdated ast-types definitions.\n */\nconst unwrap = (node: any) => {\n while (\n node &&\n (n.TSSatisfiesExpression?.check(node) ||\n n.TSAsExpression?.check(node) ||\n n.TSTypeAssertion?.check(node) ||\n n.TSNonNullExpression?.check(node) ||\n [\n 'TSSatisfiesExpression',\n 'TSAsExpression',\n 'TSTypeAssertion',\n 'TSNonNullExpression',\n ].includes(node.type))\n ) {\n node = node.expression;\n }\n return node;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n\n return false;\n });\n};\n\n/**\n * Synchronizes numeric suffixes across locales.\n * E.g. \"Hello 1\" -> \"Hello 3\" updates \"Bonjour 1\" to \"Bonjour 3\".\n */\nconst syncNumericSuffixAcrossLocales = (\n existingNode: any,\n fallbackLocaleCode: string,\n newFallbackValue: string\n) => {\n const trailingNumberMatch = newFallbackValue.match(/\\d+(?!.*\\d)/);\n if (!trailingNumberMatch) return;\n const newTrailingNumber = trailingNumberMatch[0];\n\n if (n.ObjectExpression.check(existingNode)) {\n for (const prop of existingNode.properties) {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (\n n.Literal.check(prop.key) &&\n typeof prop.key.value === 'string'\n )\n propName = prop.key.value;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n\n if (propName && propName !== fallbackLocaleCode) {\n if (\n n.Literal.check(prop.value) &&\n typeof prop.value.value === 'string'\n ) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.literal(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n } else if (n.StringLiteral.check(prop.value)) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.stringLiteral(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n }\n }\n }\n }\n }\n};\n\n/**\n * Checks if a value represents a multilingual Intlayer node.\n *\n * A node is multilingual if it is a Translation node, if it wraps one\n * (Markdown, HTML, Insertion…), or if any of its variants contains one\n * (Enumeration, Plural, Condition, Gender, Select…).\n */\nconst isMultilingualNode = (val: any): boolean => {\n if (typeof val !== 'object' || val === null || Array.isArray(val)) {\n return false;\n }\n\n const nodeType = getNodeType(val as ContentNode);\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n const strategy = nodeTypeStrategies[nodeType];\n const nodeData = (val as any)[nodeType];\n\n if (strategy.kind === 'helperValue' || strategy.kind === 'unwrap') {\n return isMultilingualNode(nodeData);\n }\n\n if (\n strategy.kind === 'helperRecord' &&\n nodeData &&\n typeof nodeData === 'object'\n ) {\n return Object.values(nodeData).some((variant) =>\n isMultilingualNode(variant)\n );\n }\n\n return false;\n};\n\n/**\n * Checks whether two AST nodes are literals holding the same value.\n */\nconst isEquivalentLiteral = (left: any, right: any): boolean => {\n const isLiteral = (node: any) =>\n n.Literal.check(node) ||\n n.StringLiteral.check(node) ||\n n.NumericLiteral.check(node) ||\n n.BooleanLiteral.check(node);\n\n return isLiteral(left) && isLiteral(right) && left.value === right.value;\n};\n\n/**\n * Aligns the arguments of an existing call expression with the desired ones.\n *\n * Mutates the call only when the arguments actually differ, so Recast keeps the\n * original formatting (and quote style) of calls that did not change.\n */\nconst syncCallArguments = (callNode: any, desiredArguments: any[]) => {\n const isUnchanged =\n callNode.arguments.length === desiredArguments.length &&\n desiredArguments.every((desired, index) => {\n const current = callNode.arguments[index];\n\n return current === desired || isEquivalentLiteral(current, desired);\n });\n\n if (!isUnchanged) {\n callNode.arguments = desiredArguments;\n }\n};\n\n/**\n * Recursively builds or updates an AST node for a given dictionary value.\n *\n * Returns {@link SKIP_WRITE} when the value cannot be represented in source and\n * no existing expression can be kept.\n */\nconst buildNodeForValue = (\n val: any,\n existingNode: any,\n fallbackLocale: string | undefined, // In per-locale mode, this is the locale of the file\n requiredImports: Set<string>\n): any => {\n // Values with no source representation must never overwrite existing code.\n if (val === undefined || typeof val === 'function') {\n return existingNode ?? SKIP_WRITE;\n }\n\n const unwrappedExisting = unwrap(existingNode);\n\n // --- CRITICAL GUARD: STRICT AST PRESERVATION ---\n // If the existing node is code (JSX, Variables, standard functions), leave it alone.\n // Only allow updates to literals, plain objects, arrays, and Intlayer helpers.\n if (unwrappedExisting) {\n const isUpdatableNode =\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting) ||\n n.NumericLiteral.check(unwrappedExisting) ||\n n.BooleanLiteral.check(unwrappedExisting) ||\n n.TemplateLiteral.check(unwrappedExisting) ||\n n.ObjectExpression.check(unwrappedExisting) ||\n n.ArrayExpression.check(unwrappedExisting) ||\n (n.CallExpression.check(unwrappedExisting) &&\n n.Identifier.check(unwrappedExisting.callee) &&\n helperNames.has(unwrappedExisting.callee.name));\n\n if (!isUpdatableNode) {\n return existingNode;\n }\n }\n\n // If we are in per-locale mode (fallbackLocale is set)\n // and the value is not already a complex translation node,\n // we want to store it as a simple literal, NOT wrapped in t().\n if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n }\n\n if (fallbackLocale && existingNode && !isMultilingualNode(val)) {\n if (\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 't'\n ) {\n const arg = unwrap(existingNode.arguments[0]);\n\n if (n.ObjectExpression.check(arg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(arg, fallbackLocale, val);\n }\n updateObjectLiteral(\n arg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n\n if (!fallbackLocale) {\n requiredImports.add('t');\n }\n\n return existingNode;\n }\n }\n\n // Wrapped translations — `md(t({ … }))`, `html(t({ … }))`, `insert(t({ … }))`:\n // update the inner translation in place instead of replacing the wrapper.\n if (\n (!val || typeof val !== 'object') &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n wrapperHelperNames.has(existingNode.callee.name)\n ) {\n const wrapperName = existingNode.callee.name;\n const innerArg = existingNode.arguments[0];\n\n if (\n n.CallExpression.check(innerArg) &&\n n.Identifier.check(innerArg.callee) &&\n innerArg.callee.name === 't'\n ) {\n const tArg = unwrap(innerArg.arguments[0]);\n\n if (n.ObjectExpression.check(tArg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);\n }\n updateObjectLiteral(\n tArg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n requiredImports.add(wrapperName);\n requiredImports.add('t');\n\n return existingNode;\n }\n }\n }\n }\n\n // 1. Primitives\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (unwrappedExisting) {\n // Preserve existing template literals (backticks)\n if (\n n.TemplateLiteral.check(unwrappedExisting) &&\n unwrappedExisting.quasis[0] &&\n unwrappedExisting.expressions.length === 0\n ) {\n unwrappedExisting.quasis[0].value.raw = String(val);\n unwrappedExisting.quasis[0].value.cooked = String(val);\n return existingNode;\n }\n // Preserve existing standard literals (keeps quote styling)\n if (\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting)\n ) {\n unwrappedExisting.value = val;\n return existingNode;\n }\n }\n\n // Force multiline strings to use Template Literals\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n\n // 2. Arrays\n if (Array.isArray(val)) {\n if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {\n const elements = [...unwrappedExisting.elements];\n val.forEach((item, i) => {\n const elementNode = buildNodeForValue(\n item,\n elements[i],\n fallbackLocale,\n requiredImports\n );\n\n elements[i] =\n elementNode === SKIP_WRITE\n ? (elements[i] ?? b.literal(null))\n : elementNode;\n });\n\n if (elements.length > val.length) elements.length = val.length;\n unwrappedExisting.elements = elements as any;\n\n return existingNode;\n } else {\n return b.arrayExpression(\n val.map((item) => {\n const elementNode = buildNodeForValue(\n item,\n null,\n fallbackLocale,\n requiredImports\n );\n\n return elementNode === SKIP_WRITE ? b.literal(null) : elementNode;\n })\n );\n }\n }\n\n // 3. Intlayer Specialized Nodes — dispatched through the exhaustive registry\n const nodeType =\n val && typeof val === 'object' && !Array.isArray(val)\n ? getNodeType(val as ContentNode)\n : null;\n\n if (nodeType) {\n const strategy = nodeTypeStrategies[nodeType];\n\n // Framework elements (React/Preact/Solid) cannot be serialized back to\n // source: keep whatever the file already declares.\n if (strategy.kind === 'preserve') {\n return existingNode ?? SKIP_WRITE;\n }\n\n const hasNodeData = Object.hasOwn(val as object, nodeType);\n const nodeData = (val as any)[nodeType];\n\n // A typed node missing its payload is malformed — fall back to the generic\n // object branch rather than printing a broken helper call.\n if (strategy.kind !== 'structural' && hasNodeData) {\n if (strategy.kind === 'unwrap') {\n return buildNodeForValue(\n nodeData,\n existingNode,\n fallbackLocale,\n requiredImports\n );\n }\n\n const { helper } = strategy;\n\n requiredImports.add(helper);\n\n const isMatchingCall =\n existingNode &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === helper;\n\n if (strategy.kind === 'helperRecord') {\n const recordArgument =\n isMatchingCall &&\n existingNode.arguments.length > 0 &&\n n.ObjectExpression.check(existingNode.arguments[0])\n ? existingNode.arguments[0]\n : b.objectExpression([]);\n\n updateObjectLiteral(\n recordArgument,\n nodeData ?? {},\n fallbackLocale,\n requiredImports\n );\n\n const callArguments = [\n recordArgument,\n ...(strategy.getExtraArguments?.(val as Record<string, unknown>) ??\n []),\n ];\n\n if (isMatchingCall) {\n syncCallArguments(existingNode, callArguments);\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(helper), callArguments);\n }\n\n if (strategy.kind === 'helperValue') {\n const contentArgument = buildNodeForValue(\n nodeData,\n isMatchingCall && existingNode.arguments.length > 0\n ? existingNode.arguments[0]\n : null,\n fallbackLocale,\n requiredImports\n );\n\n if (contentArgument === SKIP_WRITE) {\n return existingNode ?? SKIP_WRITE;\n }\n\n if (isMatchingCall) {\n // Keep any extra argument the source declares (custom components\n // passed to `md()` / `html()`), which the node does not carry back.\n syncCallArguments(existingNode, [\n contentArgument,\n ...existingNode.arguments.slice(1),\n ]);\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(helper), [contentArgument]);\n }\n\n // strategy.kind === 'nesting'\n const callArguments = [b.literal(nodeData?.dictionaryKey ?? '')];\n\n if (nodeData?.path) callArguments.push(b.literal(nodeData.path));\n\n if (isMatchingCall) {\n syncCallArguments(existingNode, callArguments);\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(helper), callArguments);\n }\n }\n\n // 4. Plain Object\n const objNode =\n unwrappedExisting && n.ObjectExpression.check(unwrappedExisting)\n ? unwrappedExisting\n : b.objectExpression([]);\n\n updateObjectLiteral(objNode, val, fallbackLocale, requiredImports);\n\n return existingNode && unwrappedExisting === existingNode\n ? objNode\n : existingNode || objNode;\n};\n\n/**\n * Recursively updates the AST object literal properties.\n */\nconst updateObjectLiteral = (\n node: recast.types.namedTypes.ObjectExpression,\n data: Record<string, any>,\n fallbackLocale: string | undefined,\n requiredImports: Set<string>\n) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) continue;\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp) {\n const valueNode = buildNodeForValue(\n val,\n existingProp.value,\n fallbackLocale,\n requiredImports\n );\n\n if (valueNode !== SKIP_WRITE) {\n existingProp.value = valueNode;\n }\n } else {\n const isValidId = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);\n const keyNode = isValidId ? b.identifier(key) : b.literal(key);\n const valueNode = buildNodeForValue(\n val,\n null,\n fallbackLocale,\n requiredImports\n );\n\n if (valueNode === SKIP_WRITE) continue;\n\n node.properties.push(b.property('init', keyNode, valueNode));\n }\n }\n};\n\n/**\n * Modifies the AST's top-level imports to inject dynamically needed helper utilities seamlessly.\n */\nconst addImports = (ast: any, requiredImports: Set<string>, isESM: boolean) => {\n if (requiredImports.size === 0) return;\n\n const existingCoreImports = new Set<string>();\n let coreImportPath: any = null;\n\n recast.visit(ast, {\n visitImportDeclaration(path) {\n const source = path.node.source.value;\n\n if (source === 'intlayer') {\n coreImportPath = path;\n path.node.specifiers?.forEach((spec) => {\n if (\n n.ImportSpecifier.check(spec) &&\n typeof spec.imported.name === 'string'\n ) {\n existingCoreImports.add(spec.imported.name);\n }\n });\n }\n\n return false;\n },\n visitVariableDeclaration(path) {\n path.node.declarations.forEach((decl) => {\n if (\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require'\n ) {\n const arg = decl.init.arguments[0];\n\n if (n.Literal.check(arg)) {\n if (arg.value === 'intlayer') {\n if (n.ObjectPattern.check(decl.id)) {\n decl.id.properties.forEach((prop) => {\n if (\n n.Property.check(prop) &&\n (n.Identifier.check(prop.key) ||\n n.Identifier.check(prop.value))\n ) {\n const name = n.Identifier.check(prop.key)\n ? prop.key.name\n : (prop.value as any).name;\n existingCoreImports.add(name);\n }\n });\n } else if (n.Identifier.check(decl.id)) {\n // Handle const intlayer = require('intlayer')\n existingCoreImports.add(decl.id.name);\n }\n }\n }\n }\n });\n\n return false;\n },\n });\n\n const missingCore = Array.from(requiredImports).filter(\n (imp) => !existingCoreImports.has(imp)\n );\n\n if (missingCore.length === 0) return;\n\n if (isESM) {\n if (coreImportPath) {\n missingCore.forEach((imp) => {\n coreImportPath.node.specifiers.push(\n b.importSpecifier(b.identifier(imp))\n );\n });\n coreImportPath.node.specifiers.sort((a: any, b: any) =>\n a.imported.name.localeCompare(b.imported.name)\n );\n } else {\n const specifiers = missingCore\n .sort()\n .map((imp) => b.importSpecifier(b.identifier(imp)));\n const newImport = b.importDeclaration(specifiers, b.literal('intlayer'));\n ast.program.body.unshift(newImport);\n }\n } else {\n let insertIndex = 0;\n\n if (\n ast.program.body.length > 0 &&\n n.ExpressionStatement.check(ast.program.body[0]) &&\n n.Literal.check(ast.program.body[0].expression)\n ) {\n insertIndex = 1; // Insert after 'use strict'\n }\n const cjsLines: any[] = [];\n\n const properties = missingCore.sort().map((imp) => {\n const prop = b.property('init', b.identifier(imp), b.identifier(imp));\n prop.shorthand = true;\n\n return prop;\n });\n cjsLines.push(\n b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern(properties),\n b.callExpression(b.identifier('require'), [b.literal('intlayer')])\n ),\n ])\n );\n\n ast.program.body.splice(insertIndex, 0, ...cjsLines);\n }\n};\n\n/**\n * Updates a JS/TS file seamlessly to map new localization keys, arrays, complex nodes and nested dictionaries gracefully using AST updates via Recast parser.\n */\nexport const transformJSFile = async (\n fileContent: string,\n dictionary: Dictionary,\n fallbackLocale?: Locale,\n noMetadata?: boolean\n): Promise<string> => {\n if (!dictionary || typeof dictionary !== 'object') return fileContent;\n\n let ast: any;\n try {\n ast = recast.parse(fileContent, {\n parser: babelTsParser,\n });\n } catch (error) {\n console.error({ error });\n return fileContent;\n }\n\n let rootObject: any = null;\n let isESM = false;\n\n recast.visit(ast, {\n visitExportDefaultDeclaration() {\n isESM = true;\n\n return false;\n },\n visitImportDeclaration() {\n isESM = true;\n\n return false;\n },\n });\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n const unwrappedDecl = unwrap(decl);\n\n if (n.ObjectExpression.check(unwrappedDecl)) {\n rootObject = unwrappedDecl;\n } else if (n.Identifier.check(unwrappedDecl)) {\n const varName = unwrappedDecl.name;\n recast.visit(ast, {\n visitVariableDeclarator(vp) {\n const unwrappedInit = unwrap(vp.node.init);\n\n if (\n n.Identifier.check(vp.node.id) &&\n vp.node.id.name === varName &&\n n.ObjectExpression.check(unwrappedInit)\n ) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n return false;\n },\n visitAssignmentExpression(path) {\n const left = path.node.left;\n\n if (n.MemberExpression.check(left)) {\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'module' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'exports'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'exports' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'default'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n }\n this.traverse(path);\n },\n });\n\n if (!rootObject) {\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const unwrappedInit = unwrap(path.node.init);\n\n if (!rootObject && n.ObjectExpression.check(unwrappedInit)) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n if (!rootObject) return fileContent;\n\n const requiredImports = new Set<string>();\n const effectiveFallbackLocale = (fallbackLocale as string) ?? 'en';\n\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n ];\n\n if (noMetadata) {\n // Remove key, content and metadata properties if they exist\n rootObject.properties = rootObject.properties.filter((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n return !['key', 'content', ...metadataProperties].includes(propName);\n }\n return true;\n });\n\n // Update satisfies type if exists\n recast.visit(ast, {\n visitNode(path) {\n const node = path.node;\n if (\n (n.TSSatisfiesExpression?.check(node) ||\n node.type === 'TSSatisfiesExpression') &&\n (node as any).typeAnnotation &&\n n.TSTypeReference.check((node as any).typeAnnotation) &&\n n.Identifier.check((node as any).typeAnnotation.typeName) &&\n (node as any).typeAnnotation.typeName.name === 'Dictionary'\n ) {\n (node as any).typeAnnotation = b.tsIndexedAccessType(\n b.tsTypeReference(b.identifier('Dictionary')),\n b.tsLiteralType(b.stringLiteral('content'))\n );\n }\n this.traverse(path);\n },\n });\n } else {\n for (const prop of metadataProperties) {\n if ((dictionary as any)[prop] !== undefined) {\n updateObjectLiteral(\n rootObject,\n { [prop]: (dictionary as any)[prop] },\n undefined,\n requiredImports\n );\n }\n }\n }\n\n if (dictionary.content !== undefined) {\n updateObjectLiteral(\n rootObject,\n noMetadata\n ? (dictionary.content as Record<string, any>)\n : { content: dictionary.content },\n effectiveFallbackLocale,\n requiredImports\n );\n }\n\n addImports(ast, requiredImports, isESM);\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
|
|
@@ -60,11 +60,12 @@ const updateObjectLiteral = (node, data) => {
|
|
|
60
60
|
c.trailing = true;
|
|
61
61
|
}
|
|
62
62
|
});
|
|
63
|
-
if (isPlainObject(val))
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
if (isPlainObject(val)) {
|
|
64
|
+
if (existingProp && n.ObjectExpression.check(existingProp.value)) updateObjectLiteral(existingProp.value, val);
|
|
65
|
+
else if (existingProp) {
|
|
66
|
+
if (!(n.Literal.check(existingProp.value) && existingProp.value.value === val)) existingProp.value = buildASTNode(val);
|
|
67
|
+
} else node.properties.push(b.property("init", b.stringLiteral(key), buildASTNode(val)));
|
|
68
|
+
} else if (existingProp) {
|
|
68
69
|
if (!isPrimitiveEqual(existingProp.value, val)) existingProp.value = buildASTNode(val);
|
|
69
70
|
} else node.properties.push(b.property("init", b.stringLiteral(key), buildASTNode(val)));
|
|
70
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformJSONFile.cjs","names":[],"sources":["../../../src/writeContentDeclaration/transformJSONFile.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport * as recast from 'recast';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Checks if a value is a plain object (and not null/array)\n */\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n\n/**\n * Checks if a recast AST node value matches the incoming primitive value.\n */\nconst isPrimitiveEqual = (astNode: any, val: unknown): boolean => {\n if (val === null) {\n return n.Literal.check(astNode) && astNode.value === null;\n }\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n return (\n (n.Literal.check(astNode) ||\n n.StringLiteral.check(astNode) ||\n n.NumericLiteral.check(astNode) ||\n n.BooleanLiteral.check(astNode)) &&\n astNode.value === val\n );\n }\n return false;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n return false;\n });\n};\n\n/**\n * Recursively builds a clean recast AST node from a plain JS value.\n * Because these nodes lack `loc` tracking, recast is forced to pretty-print them.\n */\nconst buildASTNode = (val: unknown): any => {\n if (val === null) return b.literal(null);\n\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n return b.literal(val);\n }\n\n if (Array.isArray(val)) {\n return b.arrayExpression(val.map((item) => buildASTNode(item)));\n }\n\n if (isPlainObject(val)) {\n return b.objectExpression(\n Object.entries(val)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) =>\n b.property('init', b.stringLiteral(k), buildASTNode(v))\n )\n );\n }\n\n return b.literal(null); // Fallback\n};\n\n/**\n * Recursively updates the AST object literal with new data.\n */\nconst updateObjectLiteral = (node: any, data: Record<string, any>) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) {\n continue;\n }\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp?.comments) {\n existingProp.comments.forEach((c: any) => {\n if ((c.type === 'Line' || c.type === 'CommentLine') && c.trailing) {\n // Convert to block comment and tag it to force Recast to print it inline\n c.type = c.type === 'Line' ? 'Block' : 'CommentBlock';\n c.value = `__INLINE_LINE__${c.value}`;\n c.leading = false;\n c.trailing = true;\n }\n });\n }\n\n if (isPlainObject(val)) {\n if (existingProp && n.ObjectExpression.check(existingProp.value)) {\n updateObjectLiteral(existingProp.value, val);\n } else {\n if (existingProp) {\n // Prevent AST invalidation if the primitive value is identical\n const isIdentical =\n n.Literal.check(existingProp.value) &&\n existingProp.value.value === val;\n\n if (!isIdentical) {\n existingProp.value = buildASTNode(val);\n }\n } else {\n node.properties.push(\n b.property('init', b.stringLiteral(key), buildASTNode(val))\n );\n }\n }\n } else {\n // Handle primitives and arrays\n if (existingProp) {\n // Skip assignment if the primitive value is identical\n if (!isPrimitiveEqual(existingProp.value, val)) {\n existingProp.value = buildASTNode(val);\n }\n } else {\n node.properties.push(\n b.property('init', b.stringLiteral(key), buildASTNode(val))\n );\n }\n }\n }\n};\n\nexport const transformJSONFile = (\n fileContent: string,\n dictionary: Dictionary,\n noMetadata?: boolean\n): string => {\n // Wrap content to create valid syntax for the parser\n const wrappedContent = `const _config = ${fileContent.trim() || '{}'};`;\n\n let ast: ReturnType<typeof recast.parse>;\n try {\n ast = recast.parse(wrappedContent);\n } catch {\n // Fallback if parsing failed\n return JSON.stringify(\n noMetadata ? dictionary.content : dictionary,\n null,\n 2\n );\n }\n\n // Navigate the AST to locate the object literal initialized to `_config`\n const declaration = ast.program.body[0];\n let objectLiteral: any;\n\n if (\n n.VariableDeclaration.check(declaration) &&\n declaration.declarations.length > 0 &&\n n.VariableDeclarator.check(declaration.declarations[0]) &&\n n.ObjectExpression.check(declaration.declarations[0].init)\n ) {\n objectLiteral = declaration.declarations[0].init;\n }\n\n if (noMetadata) {\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n '$schema',\n ];\n\n // Mutate the array backwards instead of using .filter() to prevent layout invalidation\n for (let i = objectLiteral.properties.length - 1; i >= 0; i--) {\n const prop = objectLiteral.properties[i];\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n if (['key', 'content', ...metadataProperties].includes(propName)) {\n objectLiteral.properties.splice(i, 1);\n }\n }\n }\n }\n\n // Update the AST in place\n updateObjectLiteral(\n objectLiteral,\n noMetadata ? (dictionary.content as Record<string, any>) : dictionary\n );\n\n // Print the full AST to utilize the global token stream for inline comments\n const printedCode = recast.print(ast, {\n tabWidth: 2,\n quote: 'double',\n trailingComma: false,\n }).code;\n\n // Extract the target object literal cleanly\n const startIndex = printedCode.indexOf('{');\n const endIndex = printedCode.lastIndexOf('}');\n let finalOutput = printedCode.substring(startIndex, endIndex + 1);\n\n // Revert the tagged block comment back to an inline line comment and fix comma placement\n finalOutput = finalOutput.replace(\n /\\s*\\/\\*__INLINE_LINE__(.*?)\\*\\/(\\s*,?)/g,\n '$2 //$1'\n );\n\n // Collapse empty lines injected by Recast around commented properties\n finalOutput = finalOutput.replace(/\\n[ \\t]*\\n/g, '\\n');\n\n return finalOutput;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transformJSONFile.cjs","names":[],"sources":["../../../src/writeContentDeclaration/transformJSONFile.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport * as recast from 'recast';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Checks if a value is a plain object (and not null/array)\n */\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n\n/**\n * Checks if a recast AST node value matches the incoming primitive value.\n */\nconst isPrimitiveEqual = (astNode: any, val: unknown): boolean => {\n if (val === null) {\n return n.Literal.check(astNode) && astNode.value === null;\n }\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n return (\n (n.Literal.check(astNode) ||\n n.StringLiteral.check(astNode) ||\n n.NumericLiteral.check(astNode) ||\n n.BooleanLiteral.check(astNode)) &&\n astNode.value === val\n );\n }\n return false;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n return false;\n });\n};\n\n/**\n * Recursively builds a clean recast AST node from a plain JS value.\n * Because these nodes lack `loc` tracking, recast is forced to pretty-print them.\n */\nconst buildASTNode = (val: unknown): any => {\n if (val === null) return b.literal(null);\n\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n return b.literal(val);\n }\n\n if (Array.isArray(val)) {\n return b.arrayExpression(val.map((item) => buildASTNode(item)));\n }\n\n if (isPlainObject(val)) {\n return b.objectExpression(\n Object.entries(val)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) =>\n b.property('init', b.stringLiteral(k), buildASTNode(v))\n )\n );\n }\n\n return b.literal(null); // Fallback\n};\n\n/**\n * Recursively updates the AST object literal with new data.\n */\nconst updateObjectLiteral = (node: any, data: Record<string, any>) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) {\n continue;\n }\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp?.comments) {\n existingProp.comments.forEach((c: any) => {\n if ((c.type === 'Line' || c.type === 'CommentLine') && c.trailing) {\n // Convert to block comment and tag it to force Recast to print it inline\n c.type = c.type === 'Line' ? 'Block' : 'CommentBlock';\n c.value = `__INLINE_LINE__${c.value}`;\n c.leading = false;\n c.trailing = true;\n }\n });\n }\n\n if (isPlainObject(val)) {\n if (existingProp && n.ObjectExpression.check(existingProp.value)) {\n updateObjectLiteral(existingProp.value, val);\n } else {\n if (existingProp) {\n // Prevent AST invalidation if the primitive value is identical\n const isIdentical =\n n.Literal.check(existingProp.value) &&\n existingProp.value.value === val;\n\n if (!isIdentical) {\n existingProp.value = buildASTNode(val);\n }\n } else {\n node.properties.push(\n b.property('init', b.stringLiteral(key), buildASTNode(val))\n );\n }\n }\n } else {\n // Handle primitives and arrays\n if (existingProp) {\n // Skip assignment if the primitive value is identical\n if (!isPrimitiveEqual(existingProp.value, val)) {\n existingProp.value = buildASTNode(val);\n }\n } else {\n node.properties.push(\n b.property('init', b.stringLiteral(key), buildASTNode(val))\n );\n }\n }\n }\n};\n\nexport const transformJSONFile = (\n fileContent: string,\n dictionary: Dictionary,\n noMetadata?: boolean\n): string => {\n // Wrap content to create valid syntax for the parser\n const wrappedContent = `const _config = ${fileContent.trim() || '{}'};`;\n\n let ast: ReturnType<typeof recast.parse>;\n try {\n ast = recast.parse(wrappedContent);\n } catch {\n // Fallback if parsing failed\n return JSON.stringify(\n noMetadata ? dictionary.content : dictionary,\n null,\n 2\n );\n }\n\n // Navigate the AST to locate the object literal initialized to `_config`\n const declaration = ast.program.body[0];\n let objectLiteral: any;\n\n if (\n n.VariableDeclaration.check(declaration) &&\n declaration.declarations.length > 0 &&\n n.VariableDeclarator.check(declaration.declarations[0]) &&\n n.ObjectExpression.check(declaration.declarations[0].init)\n ) {\n objectLiteral = declaration.declarations[0].init;\n }\n\n if (noMetadata) {\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n '$schema',\n ];\n\n // Mutate the array backwards instead of using .filter() to prevent layout invalidation\n for (let i = objectLiteral.properties.length - 1; i >= 0; i--) {\n const prop = objectLiteral.properties[i];\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n if (['key', 'content', ...metadataProperties].includes(propName)) {\n objectLiteral.properties.splice(i, 1);\n }\n }\n }\n }\n\n // Update the AST in place\n updateObjectLiteral(\n objectLiteral,\n noMetadata ? (dictionary.content as Record<string, any>) : dictionary\n );\n\n // Print the full AST to utilize the global token stream for inline comments\n const printedCode = recast.print(ast, {\n tabWidth: 2,\n quote: 'double',\n trailingComma: false,\n }).code;\n\n // Extract the target object literal cleanly\n const startIndex = printedCode.indexOf('{');\n const endIndex = printedCode.lastIndexOf('}');\n let finalOutput = printedCode.substring(startIndex, endIndex + 1);\n\n // Revert the tagged block comment back to an inline line comment and fix comma placement\n finalOutput = finalOutput.replace(\n /\\s*\\/\\*__INLINE_LINE__(.*?)\\*\\/(\\s*,?)/g,\n '$2 //$1'\n );\n\n // Collapse empty lines injected by Recast around commented properties\n finalOutput = finalOutput.replace(/\\n[ \\t]*\\n/g, '\\n');\n\n return finalOutput;\n};\n"],"mappings":"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"}
|
|
@@ -53,7 +53,11 @@ const formatContentDeclaration = async (dictionary, configuration, localeList) =
|
|
|
53
53
|
...Object.fromEntries(Object.entries(dictionary).filter(([k]) => !INTERNAL_FIELDS.has(k))),
|
|
54
54
|
content
|
|
55
55
|
};
|
|
56
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Add $schema to JSON dictionaries
|
|
58
|
+
*/
|
|
59
|
+
const extension = dictionary.filePath ? (0, node_path.extname)(dictionary.filePath) : ".json";
|
|
60
|
+
if (require_utils_getFormatFromExtension.getFormatFromExtension(extension) === "json" && pluginFormatResult.content && pluginFormatResult.key) result = {
|
|
57
61
|
$schema: "https://intlayer.org/schema.json",
|
|
58
62
|
...result
|
|
59
63
|
};
|
|
@@ -100,7 +104,8 @@ const writeContentDeclaration = async (dictionary, configuration, options) => {
|
|
|
100
104
|
};
|
|
101
105
|
};
|
|
102
106
|
const writeFileWithDirectories = async (absoluteFilePath, dictionary, configuration, noMetadata) => {
|
|
103
|
-
|
|
107
|
+
const dir = (0, node_path.dirname)(absoluteFilePath);
|
|
108
|
+
await (0, node_fs_promises.mkdir)(dir, { recursive: true });
|
|
104
109
|
const extension = (0, node_path.extname)(absoluteFilePath);
|
|
105
110
|
if (extension === ".md" || extension === ".mdx") {
|
|
106
111
|
await require_writeContentDeclaration_writeMarkdownFile.writeMarkdownFile(absoluteFilePath, dictionary, configuration);
|
|
@@ -154,7 +159,8 @@ const writeFileWithDirectories = async (absoluteFilePath, dictionary, configurat
|
|
|
154
159
|
])).has(extension)) return;
|
|
155
160
|
await require_writeContentDeclaration_writeJSFile.writeJSFile(absoluteFilePath, dictionary, configuration, noMetadata);
|
|
156
161
|
try {
|
|
157
|
-
|
|
162
|
+
const sentinelPath = (0, node_path.join)(configuration.system.cacheDir, "intlayer-prepared.lock");
|
|
163
|
+
await (0, node_fs_promises.rm)(sentinelPath, { recursive: true });
|
|
158
164
|
} catch {}
|
|
159
165
|
};
|
|
160
166
|
|