@intlayer/engine 9.3.0 → 9.3.2

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.
Files changed (297) hide show
  1. package/README.md +24 -24
  2. package/dist/assets/initConfig/templates/cjs.txt +1 -1
  3. package/dist/assets/initConfig/templates/mjs.txt +1 -1
  4. package/dist/assets/initConfig/templates/ts.txt +1 -1
  5. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  6. package/dist/cjs/_virtual/_utils_asset.cjs +2 -1
  7. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  8. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +2 -1
  9. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
  10. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
  11. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -1
  12. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
  13. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -1
  14. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +4 -2
  15. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
  16. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
  17. package/dist/cjs/cleanOutputDir.cjs.map +1 -1
  18. package/dist/cjs/cleanRemovedContentDeclaration.cjs +7 -4
  19. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  20. package/dist/cjs/cli.cjs +2 -0
  21. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +5 -3
  22. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
  23. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
  24. package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
  25. package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
  26. package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
  27. package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
  28. package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
  29. package/dist/cjs/createType/createModuleAugmentation.cjs +2 -1
  30. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  31. package/dist/cjs/createType/createType.cjs.map +1 -1
  32. package/dist/cjs/detectFormatCommand.cjs.map +1 -1
  33. package/dist/cjs/docReview/alignBlocks.cjs +1 -1
  34. package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
  35. package/dist/cjs/docReview/computeSimilarity.cjs +0 -1
  36. package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
  37. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +0 -1
  38. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
  39. package/dist/cjs/docReview/normalizeBlock.cjs +0 -1
  40. package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
  41. package/dist/cjs/docReview/planActions.cjs +0 -1
  42. package/dist/cjs/docReview/planActions.cjs.map +1 -1
  43. package/dist/cjs/docReview/rebuildDocument.cjs +0 -1
  44. package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
  45. package/dist/cjs/docReview/reviewReport.cjs +2 -1
  46. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  47. package/dist/cjs/docReview/segmentDocument.cjs +0 -1
  48. package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
  49. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  50. package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
  51. package/dist/cjs/formatDictionary.cjs.map +1 -1
  52. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
  53. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +4 -2
  54. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
  55. package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -2
  56. package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
  57. package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
  58. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +4 -2
  59. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
  60. package/dist/cjs/init/cms.cjs.map +1 -1
  61. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
  62. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +1 -3
  63. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  64. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +2 -1
  65. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
  66. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +0 -1
  67. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
  68. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
  69. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +3 -5
  70. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  71. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -1
  72. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
  73. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +18 -12
  74. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
  75. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +57 -14
  76. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  77. package/dist/cjs/init/index.cjs +124 -45
  78. package/dist/cjs/init/index.cjs.map +1 -1
  79. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  80. package/dist/cjs/init/utils/fileSystem.cjs +3 -1
  81. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  82. package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
  83. package/dist/cjs/init/utils/index.cjs +3 -0
  84. package/dist/cjs/init/utils/jsonParser.cjs +0 -1
  85. package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
  86. package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
  87. package/dist/cjs/init/utils/packageManager.cjs +105 -7
  88. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  89. package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
  90. package/dist/cjs/init/utils/version.cjs +0 -1
  91. package/dist/cjs/init/utils/version.cjs.map +1 -1
  92. package/dist/cjs/initConfig/index.cjs +12 -8
  93. package/dist/cjs/initConfig/index.cjs.map +1 -1
  94. package/dist/cjs/installSkills/index.cjs.map +1 -1
  95. package/dist/cjs/listDictionariesPath.cjs +6 -5
  96. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  97. package/dist/cjs/listGitFiles.cjs.map +1 -1
  98. package/dist/cjs/listProjects.cjs +2 -1
  99. package/dist/cjs/listProjects.cjs.map +1 -1
  100. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +2 -1
  101. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
  102. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +8 -5
  103. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  104. package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
  105. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
  106. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
  107. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  108. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +2 -1
  109. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
  110. package/dist/cjs/loadDictionaries/log.cjs +10 -6
  111. package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
  112. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  113. package/dist/cjs/logConfigDetails.cjs +4 -3
  114. package/dist/cjs/logConfigDetails.cjs.map +1 -1
  115. package/dist/cjs/prepareIntlayer.cjs +5 -3
  116. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  117. package/dist/cjs/reduceDictionaryContent/applyMask.cjs +0 -1
  118. package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
  119. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +2 -1
  120. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
  121. package/dist/cjs/scan/calculateScore.cjs +0 -1
  122. package/dist/cjs/scan/calculateScore.cjs.map +1 -1
  123. package/dist/cjs/scan/checks.cjs +1 -1
  124. package/dist/cjs/scan/checks.cjs.map +1 -1
  125. package/dist/cjs/scan/parseHtml.cjs +0 -1
  126. package/dist/cjs/scan/parseHtml.cjs.map +1 -1
  127. package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
  128. package/dist/cjs/syncPluginKit/createFileAdapter.cjs +2 -1
  129. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
  130. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +4 -1
  131. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
  132. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +0 -1
  133. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
  134. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +0 -1
  135. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
  136. package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
  137. package/dist/cjs/utils/babelParser.cjs.map +1 -1
  138. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  139. package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
  140. package/dist/cjs/utils/chunkArray.cjs +0 -1
  141. package/dist/cjs/utils/chunkArray.cjs.map +1 -1
  142. package/dist/cjs/utils/formatter.cjs.map +1 -1
  143. package/dist/cjs/utils/getContentExtension.cjs +1 -4
  144. package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
  145. package/dist/cjs/utils/getFormatFromExtension.cjs +0 -1
  146. package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
  147. package/dist/cjs/utils/getPathHash.cjs +0 -1
  148. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  149. package/dist/cjs/utils/mergeChunks.cjs +0 -1
  150. package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
  151. package/dist/cjs/utils/pLimit.cjs +0 -1
  152. package/dist/cjs/utils/pLimit.cjs.map +1 -1
  153. package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
  154. package/dist/cjs/utils/reduceObjectFormat.cjs +0 -1
  155. package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
  156. package/dist/cjs/utils/resolveObjectPromises.cjs +0 -1
  157. package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
  158. package/dist/cjs/utils/resolveRelativePath.cjs +4 -1
  159. package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
  160. package/dist/cjs/utils/runOnce.cjs +2 -2
  161. package/dist/cjs/utils/runOnce.cjs.map +1 -1
  162. package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
  163. package/dist/cjs/utils/runParallel/bootstrap.cjs +0 -1
  164. package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
  165. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  166. package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
  167. package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
  168. package/dist/cjs/utils/sortAlphabetically.cjs +0 -1
  169. package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
  170. package/dist/cjs/utils/splitTextByLine.cjs +0 -1
  171. package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
  172. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs +0 -1
  173. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
  174. package/dist/cjs/watcher.cjs +4 -2
  175. package/dist/cjs/watcher.cjs.map +1 -1
  176. package/dist/cjs/writeConfiguration/index.cjs +2 -1
  177. package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
  178. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +0 -1
  179. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
  180. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
  181. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +26 -23
  182. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
  183. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs +6 -5
  184. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
  185. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +9 -3
  186. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  187. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +2 -1
  188. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
  189. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -1
  190. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  191. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +4 -2
  192. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  193. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  194. package/dist/esm/_virtual/_utils_asset.mjs +2 -1
  195. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +2 -1
  196. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
  197. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
  198. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
  199. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +4 -2
  200. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
  201. package/dist/esm/cleanRemovedContentDeclaration.mjs +7 -4
  202. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  203. package/dist/esm/cli.mjs +2 -2
  204. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs +5 -3
  205. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
  206. package/dist/esm/createType/createModuleAugmentation.mjs +2 -1
  207. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  208. package/dist/esm/docReview/alignBlocks.mjs +1 -1
  209. package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
  210. package/dist/esm/docReview/reviewReport.mjs +2 -1
  211. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  212. package/dist/esm/handleAdditionalContentDeclarationFile.mjs +4 -2
  213. package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
  214. package/dist/esm/handleContentDeclarationFileChange.mjs +6 -2
  215. package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
  216. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +4 -2
  217. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
  218. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +1 -3
  219. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  220. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +2 -1
  221. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
  222. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +4 -6
  223. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  224. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -1
  225. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
  226. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +17 -10
  227. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
  228. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +58 -15
  229. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  230. package/dist/esm/init/index.mjs +125 -46
  231. package/dist/esm/init/index.mjs.map +1 -1
  232. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  233. package/dist/esm/init/utils/fileSystem.mjs +3 -1
  234. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  235. package/dist/esm/init/utils/index.mjs +2 -2
  236. package/dist/esm/init/utils/packageManager.mjs +103 -8
  237. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  238. package/dist/esm/initConfig/index.mjs +12 -8
  239. package/dist/esm/initConfig/index.mjs.map +1 -1
  240. package/dist/esm/listDictionariesPath.mjs +6 -5
  241. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  242. package/dist/esm/listProjects.mjs +2 -1
  243. package/dist/esm/listProjects.mjs.map +1 -1
  244. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs +2 -1
  245. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
  246. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +8 -5
  247. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  248. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs +2 -1
  249. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
  250. package/dist/esm/loadDictionaries/log.mjs +10 -6
  251. package/dist/esm/loadDictionaries/log.mjs.map +1 -1
  252. package/dist/esm/logConfigDetails.mjs +4 -3
  253. package/dist/esm/logConfigDetails.mjs.map +1 -1
  254. package/dist/esm/prepareIntlayer.mjs +5 -3
  255. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  256. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs +2 -1
  257. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
  258. package/dist/esm/scan/checks.mjs +1 -1
  259. package/dist/esm/scan/checks.mjs.map +1 -1
  260. package/dist/esm/syncPluginKit/createFileAdapter.mjs +2 -1
  261. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
  262. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +4 -1
  263. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
  264. package/dist/esm/utils/babelParser.mjs.map +1 -1
  265. package/dist/esm/utils/getContentExtension.mjs +1 -3
  266. package/dist/esm/utils/getContentExtension.mjs.map +1 -1
  267. package/dist/esm/utils/resolveRelativePath.mjs +4 -1
  268. package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
  269. package/dist/esm/utils/runOnce.mjs +2 -2
  270. package/dist/esm/utils/runOnce.mjs.map +1 -1
  271. package/dist/esm/watcher.mjs +4 -2
  272. package/dist/esm/watcher.mjs.map +1 -1
  273. package/dist/esm/writeConfiguration/index.mjs +2 -1
  274. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  275. package/dist/esm/writeContentDeclaration/transformJSFile.mjs +26 -23
  276. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  277. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs +6 -5
  278. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
  279. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +9 -3
  280. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  281. package/dist/esm/writeContentDeclaration/writeJSFile.mjs +2 -1
  282. package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
  283. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -1
  284. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  285. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +4 -2
  286. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  287. package/dist/types/cli.d.ts +2 -2
  288. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +9 -4
  289. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  290. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +6 -2
  291. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  292. package/dist/types/init/index.d.ts +2 -7
  293. package/dist/types/init/index.d.ts.map +1 -1
  294. package/dist/types/init/utils/index.d.ts +2 -2
  295. package/dist/types/init/utils/packageManager.d.ts +39 -6
  296. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  297. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"babelParser.mjs","names":[],"sources":["../../../src/utils/babelParser.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport type {\n babelTsParser as babelTsParserImpl,\n RecastParser,\n typescriptParser as typescriptParserImpl,\n} from '@intlayer/babel/babelParser';\n\n/**\n * Recast-compatible parsers, backed by `@intlayer/babel`.\n *\n * All Babel operations live in `@intlayer/babel`, so this package never depends\n * on `@babel/parser` directly. `@intlayer/babel/babelParser` is loaded lazily on\n * the first `parse` call: `recast.parse` invokes `parser.parse` synchronously,\n * so a `require` (rather than a dynamic `import`) is used to keep the API\n * synchronous while deferring the load — `@babel/parser` stays off the hot path\n * until an AST transform actually runs.\n *\n * `@intlayer/babel` is an optional peer dependency of `@intlayer/engine`. The\n * flows that use these parsers (`intlayer init`, content-declaration writes) are\n * driven by `@intlayer/cli`, which ships `@intlayer/babel`, so it is present\n * whenever these parsers are needed.\n */\n\n/** Works in both the ESM and CJS builds (see `@intlayer/config`'s helper). */\nconst isESModule = typeof import.meta.url === 'string';\nconst engineRequire: NodeJS.Require = isESModule\n ? createRequire(import.meta.url)\n : require;\n\nconst BABEL_PARSER_MODULE = '@intlayer/babel/babelParser';\n\ntype BabelParserModule = {\n typescriptParser: typeof typescriptParserImpl;\n babelTsParser: typeof babelTsParserImpl;\n};\n\nlet cachedModule: BabelParserModule | undefined;\n\n/**\n * Lazily resolves `@intlayer/babel/babelParser`, caching the result.\n *\n * @throws If `@intlayer/babel` is not installed.\n */\nconst loadBabelParser = (): BabelParserModule => {\n if (cachedModule) return cachedModule;\n\n try {\n cachedModule = engineRequire(BABEL_PARSER_MODULE) as BabelParserModule;\n } catch (error) {\n throw new Error(\n `Failed to load \"${BABEL_PARSER_MODULE}\". Install \"@intlayer/babel\" to enable AST-based transforms.`,\n { cause: error }\n );\n }\n\n return cachedModule;\n};\n\nexport type { RecastParser };\n\n/** Drop-in replacement for `recast/parsers/typescript` (TS without JSX). */\nexport const typescriptParser: RecastParser = {\n parse: (source: string) => loadBabelParser().typescriptParser.parse(source),\n};\n\n/** Drop-in replacement for `recast/parsers/babel-ts` (TS *and* JSX). */\nexport const babelTsParser: RecastParser = {\n parse: (source: string) => loadBabelParser().babelTsParser.parse(source),\n};\n"],"mappings":";;;;AAyBA,MAAM,gBADa,OAAO,OAAO,KAAK,QAAQ,WAE1C,cAAc,OAAO,KAAK,GAAG;AAGjC,MAAM,sBAAsB;AAO5B,IAAI;;;;;;AAOJ,MAAM,wBAA2C;CAC/C,IAAI,cAAc,OAAO;CAEzB,IAAI;EACF,eAAe,cAAc,mBAAmB;CAClD,SAAS,OAAO;EACd,MAAM,IAAI,MACR,mBAAmB,oBAAoB,+DACvC,EAAE,OAAO,MAAM,CACjB;CACF;CAEA,OAAO;AACT;;AAKA,MAAa,mBAAiC,EAC5C,QAAQ,WAAmB,gBAAgB,CAAC,CAAC,iBAAiB,MAAM,MAAM,EAC5E;;AAGA,MAAa,gBAA8B,EACzC,QAAQ,WAAmB,gBAAgB,CAAC,CAAC,cAAc,MAAM,MAAM,EACzE"}
1
+ {"version":3,"file":"babelParser.mjs","names":[],"sources":["../../../src/utils/babelParser.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport type {\n babelTsParser as babelTsParserImpl,\n RecastParser,\n typescriptParser as typescriptParserImpl,\n} from '@intlayer/babel/babelParser';\n\n/**\n * Recast-compatible parsers, backed by `@intlayer/babel`.\n *\n * All Babel operations live in `@intlayer/babel`, so this package never depends\n * on `@babel/parser` directly. `@intlayer/babel/babelParser` is loaded lazily on\n * the first `parse` call: `recast.parse` invokes `parser.parse` synchronously,\n * so a `require` (rather than a dynamic `import`) is used to keep the API\n * synchronous while deferring the load — `@babel/parser` stays off the hot path\n * until an AST transform actually runs.\n *\n * `@intlayer/babel` is an optional peer dependency of `@intlayer/engine`. The\n * flows that use these parsers (`intlayer init`, content-declaration writes) are\n * driven by `@intlayer/cli`, which ships `@intlayer/babel`, so it is present\n * whenever these parsers are needed.\n */\n\n/** Works in both the ESM and CJS builds (see `@intlayer/config`'s helper). */\nconst isESModule = typeof import.meta.url === 'string';\nconst engineRequire: NodeJS.Require = isESModule\n ? createRequire(import.meta.url)\n : require;\n\nconst BABEL_PARSER_MODULE = '@intlayer/babel/babelParser';\n\ntype BabelParserModule = {\n typescriptParser: typeof typescriptParserImpl;\n babelTsParser: typeof babelTsParserImpl;\n};\n\nlet cachedModule: BabelParserModule | undefined;\n\n/**\n * Lazily resolves `@intlayer/babel/babelParser`, caching the result.\n *\n * @throws If `@intlayer/babel` is not installed.\n */\nconst loadBabelParser = (): BabelParserModule => {\n if (cachedModule) return cachedModule;\n\n try {\n cachedModule = engineRequire(BABEL_PARSER_MODULE) as BabelParserModule;\n } catch (error) {\n throw new Error(\n `Failed to load \"${BABEL_PARSER_MODULE}\". Install \"@intlayer/babel\" to enable AST-based transforms.`,\n { cause: error }\n );\n }\n\n return cachedModule;\n};\n\nexport type { RecastParser };\n\n/** Drop-in replacement for `recast/parsers/typescript` (TS without JSX). */\nexport const typescriptParser: RecastParser = {\n parse: (source: string) => loadBabelParser().typescriptParser.parse(source),\n};\n\n/** Drop-in replacement for `recast/parsers/babel-ts` (TS *and* JSX). */\nexport const babelTsParser: RecastParser = {\n parse: (source: string) => loadBabelParser().babelTsParser.parse(source),\n};\n"],"mappings":";;;;AAyBA,MAAM,gBADa,OAAO,YAAY,QAAQ,WAE1C,cAAc,YAAY,GAAG;AAGjC,MAAM,sBAAsB;AAO5B,IAAI;;;;;;AAOJ,MAAM,wBAA2C;CAC/C,IAAI,cAAc,OAAO;CAEzB,IAAI;EACF,eAAe,cAAc,mBAAmB;CAClD,SAAS,OAAO;EACd,MAAM,IAAI,MACR,mBAAmB,oBAAoB,+DACvC,EAAE,OAAO,MAAM,CACjB;CACF;CAEA,OAAO;AACT;;AAKA,MAAa,mBAAiC,EAC5C,QAAQ,WAAmB,gBAAgB,CAAC,CAAC,iBAAiB,MAAM,MAAM,EAC5E;;AAGA,MAAa,gBAA8B,EACzC,QAAQ,WAAmB,gBAAgB,CAAC,CAAC,cAAc,MAAM,MAAM,EACzE"}
@@ -16,9 +16,7 @@ const getContentExtension = (format, configuration) => {
16
16
  case "cjs":
17
17
  contentFileExtension = ".cjs";
18
18
  break;
19
- case "esm":
20
- contentFileExtension = ".js";
21
- break;
19
+ case "esm": contentFileExtension = ".js";
22
20
  }
23
21
  return configuration.content.fileExtensions.find((extension) => extension.endsWith(contentFileExtension)) ?? configuration.content.fileExtensions[0] ?? `.content${contentFileExtension}`;
24
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"getContentExtension.mjs","names":[],"sources":["../../../src/utils/getContentExtension.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\n\n/**\n * Generates the .content file extension based on the desired format\n * and the project's fileExtensions configuration.\n *\n * Example:\n * format 'ts' -> '.content.ts'\n * format 'esm' -> '.content.js' (if matching .content.js is found in config)\n */\nexport const getContentExtension = (\n format: 'ts' | 'esm' | 'cjs' | 'json' | 'jsonc' | 'json5' | (string & {}),\n configuration: IntlayerConfig\n): string => {\n let contentFileExtension = '.ts';\n switch (format) {\n case 'json':\n contentFileExtension = '.json';\n break;\n case 'cjs':\n contentFileExtension = '.cjs';\n break;\n case 'esm':\n contentFileExtension = '.js';\n break;\n }\n\n // Find the configured extension that matches the format's extension\n const pickedFileExtension = configuration.content.fileExtensions.find(\n (extension) => extension.endsWith(contentFileExtension)\n );\n\n return (\n pickedFileExtension ??\n configuration.content.fileExtensions[0] ??\n `.content${contentFileExtension}`\n );\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,uBACX,QACA,kBACW;CACX,IAAI,uBAAuB;CAC3B,QAAQ,QAAR;EACE,KAAK;GACH,uBAAuB;GACvB;EACF,KAAK;GACH,uBAAuB;GACvB;EACF,KAAK;GACH,uBAAuB;GACvB;CACJ;CAOA,OAJ4B,cAAc,QAAQ,eAAe,MAC9D,cAAc,UAAU,SAAS,oBAAoB,CAIpC,KAClB,cAAc,QAAQ,eAAe,MACrC,WAAW;AAEf"}
1
+ {"version":3,"file":"getContentExtension.mjs","names":[],"sources":["../../../src/utils/getContentExtension.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\n\n/**\n * Generates the .content file extension based on the desired format\n * and the project's fileExtensions configuration.\n *\n * Example:\n * format 'ts' -> '.content.ts'\n * format 'esm' -> '.content.js' (if matching .content.js is found in config)\n */\nexport const getContentExtension = (\n format: 'ts' | 'esm' | 'cjs' | 'json' | 'jsonc' | 'json5' | (string & {}),\n configuration: IntlayerConfig\n): string => {\n let contentFileExtension = '.ts';\n switch (format) {\n case 'json':\n contentFileExtension = '.json';\n break;\n case 'cjs':\n contentFileExtension = '.cjs';\n break;\n case 'esm':\n contentFileExtension = '.js';\n break;\n }\n\n // Find the configured extension that matches the format's extension\n const pickedFileExtension = configuration.content.fileExtensions.find(\n (extension) => extension.endsWith(contentFileExtension)\n );\n\n return (\n pickedFileExtension ??\n configuration.content.fileExtensions[0] ??\n `.content${contentFileExtension}`\n );\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,uBACX,QACA,kBACW;CACX,IAAI,uBAAuB;CAC3B,QAAQ,QAAR;EACE,KAAK;GACH,uBAAuB;GACvB;EACF,KAAK;GACH,uBAAuB;GACvB;EACF,KAAK,OACH,uBAAuB;CAE3B;CAOA,OAJ4B,cAAc,QAAQ,eAAe,MAC9D,cAAc,UAAU,SAAS,oBAAoB,CAIpC,KAClB,cAAc,QAAQ,eAAe,MACrC,WAAW;AAEf"}
@@ -11,7 +11,10 @@ const resolveRelativePath = (path, sourcePath, baseDir) => {
11
11
  }
12
12
  return normalizedResult;
13
13
  }
14
- if (path.startsWith("./") || path.startsWith("../")) return resolve(dirname(sourcePath), path);
14
+ if (path.startsWith("./") || path.startsWith("../")) {
15
+ const fileDir = dirname(sourcePath);
16
+ return resolve(fileDir, path);
17
+ }
15
18
  return resolve(baseDir, path);
16
19
  };
17
20
 
@@ -1 +1 @@
1
- {"version":3,"file":"resolveRelativePath.mjs","names":[],"sources":["../../../src/utils/resolveRelativePath.ts"],"sourcesContent":["import { dirname, isAbsolute, normalize, resolve } from 'node:path';\n\nexport const resolveRelativePath = (\n path: string,\n sourcePath: string,\n baseDir: string\n) => {\n // Handle absolute paths\n if (isAbsolute(path)) {\n const normalizedResult = normalize(path);\n const normalizedBaseDir = normalize(baseDir);\n\n // Check if it's relative to baseDir (starts with /)\n // but not a system path (like /usr/local)\n if (\n path.startsWith('/') &&\n !normalizedResult.startsWith(normalizedBaseDir)\n ) {\n // Try to resolve it relative to baseDir first\n const relativeToBase = resolve(baseDir, path.substring(1));\n\n // If the path doesn't exist in common system directories, treat as relative to baseDir\n if (\n !path.startsWith('/usr/') &&\n !path.startsWith('/etc/') &&\n !path.startsWith('/var/') &&\n !path.startsWith('/home/') &&\n !path.startsWith('/Users/') &&\n !path.startsWith('/tmp/') &&\n !path.startsWith('/private/') &&\n !path.startsWith('/opt/')\n ) {\n return relativeToBase;\n }\n }\n\n // It's a true system absolute path\n return normalizedResult;\n }\n\n // Handle relative paths (starting with ./ or ../)\n if (path.startsWith('./') || path.startsWith('../')) {\n const fileDir = dirname(sourcePath);\n return resolve(fileDir, path);\n }\n\n // Default case: treat as relative to baseDir\n return resolve(baseDir, path);\n};\n"],"mappings":";;;AAEA,MAAa,uBACX,MACA,YACA,YACG;CAEH,IAAI,WAAW,IAAI,GAAG;EACpB,MAAM,mBAAmB,UAAU,IAAI;EACvC,MAAM,oBAAoB,UAAU,OAAO;EAI3C,IACE,KAAK,WAAW,GAAG,KACnB,CAAC,iBAAiB,WAAW,iBAAiB,GAC9C;GAEA,MAAM,iBAAiB,QAAQ,SAAS,KAAK,UAAU,CAAC,CAAC;GAGzD,IACE,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,QAAQ,KACzB,CAAC,KAAK,WAAW,SAAS,KAC1B,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,WAAW,KAC5B,CAAC,KAAK,WAAW,OAAO,GAExB,OAAO;EAEX;EAGA,OAAO;CACT;CAGA,IAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK,GAEhD,OAAO,QADS,QAAQ,UACH,GAAG,IAAI;CAI9B,OAAO,QAAQ,SAAS,IAAI;AAC9B"}
1
+ {"version":3,"file":"resolveRelativePath.mjs","names":[],"sources":["../../../src/utils/resolveRelativePath.ts"],"sourcesContent":["import { dirname, isAbsolute, normalize, resolve } from 'node:path';\n\nexport const resolveRelativePath = (\n path: string,\n sourcePath: string,\n baseDir: string\n) => {\n // Handle absolute paths\n if (isAbsolute(path)) {\n const normalizedResult = normalize(path);\n const normalizedBaseDir = normalize(baseDir);\n\n // Check if it's relative to baseDir (starts with /)\n // but not a system path (like /usr/local)\n if (\n path.startsWith('/') &&\n !normalizedResult.startsWith(normalizedBaseDir)\n ) {\n // Try to resolve it relative to baseDir first\n const relativeToBase = resolve(baseDir, path.substring(1));\n\n // If the path doesn't exist in common system directories, treat as relative to baseDir\n if (\n !path.startsWith('/usr/') &&\n !path.startsWith('/etc/') &&\n !path.startsWith('/var/') &&\n !path.startsWith('/home/') &&\n !path.startsWith('/Users/') &&\n !path.startsWith('/tmp/') &&\n !path.startsWith('/private/') &&\n !path.startsWith('/opt/')\n ) {\n return relativeToBase;\n }\n }\n\n // It's a true system absolute path\n return normalizedResult;\n }\n\n // Handle relative paths (starting with ./ or ../)\n if (path.startsWith('./') || path.startsWith('../')) {\n const fileDir = dirname(sourcePath);\n return resolve(fileDir, path);\n }\n\n // Default case: treat as relative to baseDir\n return resolve(baseDir, path);\n};\n"],"mappings":";;;AAEA,MAAa,uBACX,MACA,YACA,YACG;CAEH,IAAI,WAAW,IAAI,GAAG;EACpB,MAAM,mBAAmB,UAAU,IAAI;EACvC,MAAM,oBAAoB,UAAU,OAAO;EAI3C,IACE,KAAK,WAAW,GAAG,KACnB,CAAC,iBAAiB,WAAW,iBAAiB,GAC9C;GAEA,MAAM,iBAAiB,QAAQ,SAAS,KAAK,UAAU,CAAC,CAAC;GAGzD,IACE,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,QAAQ,KACzB,CAAC,KAAK,WAAW,SAAS,KAC1B,CAAC,KAAK,WAAW,OAAO,KACxB,CAAC,KAAK,WAAW,WAAW,KAC5B,CAAC,KAAK,WAAW,OAAO,GAExB,OAAO;EAEX;EAGA,OAAO;CACT;CAGA,IAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK,GAAG;EACnD,MAAM,UAAU,QAAQ,UAAU;EAClC,OAAO,QAAQ,SAAS,IAAI;CAC9B;CAGA,OAAO,QAAQ,SAAS,IAAI;AAC9B"}
@@ -5,8 +5,8 @@ import packageJson from "@intlayer/core/package.json" with { type: "json" };
5
5
 
6
6
  //#region src/utils/runOnce.ts
7
7
  const DEFAULT_RUN_ONCE_OPTIONS = {
8
- cacheTimeoutMs: 60 * 1e3,
9
- lockWaitTimeoutMs: 300 * 1e3
8
+ cacheTimeoutMs: 6e4,
9
+ lockWaitTimeoutMs: 3e5
10
10
  };
11
11
  /** Delay between two reads of a sentinel owned by another process. */
12
12
  const LOCK_POLL_INTERVAL_MS = 50;
@@ -1 +1 @@
1
- {"version":3,"file":"runOnce.mjs","names":[],"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":["import { rmSync } from 'node:fs';\nimport { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport packageJson from '@intlayer/core/package.json' with { type: 'json' };\n\n/**\n * Lifecycle of the run described by a sentinel file.\n *\n * - `running` — a process owns the sentinel and its callback is still in flight.\n * Other processes must wait instead of starting a concurrent run.\n * - `done` — the callback completed; the sentinel is now a plain cache marker.\n */\ntype SentinelStatus = 'running' | 'done';\n\ntype SentinelData = {\n version: string;\n timestamp: number;\n status: SentinelStatus;\n /** PID of the process that owns the sentinel, used to detect abandoned locks. */\n pid: number;\n};\n\n/** Sentinel state as read from disk, enriched with the file's modification time. */\ntype SentinelState = SentinelData & { mtimeMs: number };\n\n/**\n * Context handed to the callback so it can interact with the lock it runs under.\n */\nexport type RunOnceContext = {\n /**\n * Re-create the sentinel file after an operation that may have deleted it —\n * typically cleaning the output directory, which wipes the cache directory the\n * sentinel lives in. Without this, concurrent processes would see no lock and\n * start a competing run while this one is still writing.\n */\n renewLock: () => Promise<void>;\n};\n\ntype RunOnceOptions = {\n /**\n * The function to execute when the sentinel is not found or is older than the cache timeout.\n */\n onIsCached?: () => void | Promise<void>;\n /**\n * The time window in milliseconds during which the sentinel is considered valid.\n *\n * @default 60000 = 1 minute\n */\n cacheTimeoutMs?: number;\n /**\n * If true, the callback will always run. If undefined, the callback will run only if the sentinel is older than the cache timeout.\n *\n * @default false\n */\n forceRun?: boolean;\n /**\n * How long to wait for another process to release the sentinel before\n * considering its run abandoned and taking the lock over.\n *\n * @default 300000 = 5 minutes\n */\n lockWaitTimeoutMs?: number;\n};\n\nconst DEFAULT_RUN_ONCE_OPTIONS = {\n cacheTimeoutMs: 60 * 1000, // 1 minute in milliseconds,\n lockWaitTimeoutMs: 5 * 60 * 1000, // 5 minutes in milliseconds\n} satisfies RunOnceOptions;\n\n/** Delay between two reads of a sentinel owned by another process. */\nconst LOCK_POLL_INTERVAL_MS = 50;\n\nconst delay = (durationMs: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, durationMs));\n\n/**\n * Sentinels owned by this process, released synchronously on exit so a crash or\n * a Ctrl-C never leaves a `running` lock that would stall the next run.\n */\nconst ownedSentinelFilePaths = new Set<string>();\n\nprocess.on('exit', () => {\n for (const sentinelFilePath of ownedSentinelFilePaths) {\n try {\n rmSync(sentinelFilePath, { force: true });\n } catch {}\n }\n});\n\n/**\n * Reads the sentinel file, returning `undefined` when it does not exist or\n * cannot be parsed.\n *\n * Sentinels written by older versions carry no `status`; they always describe a\n * finished run, so they are reported as `done`.\n */\nconst readSentinelState = async (\n sentinelFilePath: string\n): Promise<SentinelState | undefined> => {\n try {\n const [sentinelStats, raw] = await Promise.all([\n stat(sentinelFilePath),\n readFile(sentinelFilePath, 'utf8'),\n ]);\n\n const parsed = JSON.parse(raw) as Partial<SentinelData>;\n\n return {\n version: parsed.version ?? '',\n timestamp: parsed.timestamp ?? 0,\n status: parsed.status ?? 'done',\n pid: parsed.pid ?? 0,\n mtimeMs: sentinelStats.mtime.getTime(),\n };\n } catch {\n return undefined;\n }\n};\n\n/**\n * Whether the process that wrote the sentinel is still alive. An unknown PID\n * (legacy sentinel) is assumed alive so the staleness timeout stays the only\n * way to reclaim it.\n */\nconst isOwnerProcessAlive = (pid: number): boolean => {\n if (!pid || pid === process.pid) return true;\n\n try {\n // Signal 0 performs an existence check without delivering a signal.\n process.kill(pid, 0);\n return true;\n } catch (error) {\n // EPERM means the process exists but belongs to another user.\n return (error as NodeJS.ErrnoException).code === 'EPERM';\n }\n};\n\nconst serializeSentinel = (timestamp: number, status: SentinelStatus): string =>\n JSON.stringify({\n version: packageJson.version,\n timestamp,\n status,\n pid: process.pid,\n } satisfies SentinelData);\n\n/**\n * Attempts to take ownership of the sentinel.\n *\n * `wx` makes the creation atomic, so exactly one process can win even when\n * several start at the same moment.\n *\n * @returns `true` when this process now owns the sentinel, `false` when another\n * process created it first.\n */\nconst acquireSentinel = async (\n sentinelFilePath: string,\n timestamp: number\n): Promise<boolean> => {\n const data = serializeSentinel(timestamp, 'running');\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n // Ensure the directory exists before writing the file\n await mkdir(dirname(sentinelFilePath), { recursive: true });\n\n await writeFile(sentinelFilePath, data, { flag: 'wx' });\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n\n if (code === 'EEXIST') return false;\n // The directory was removed between the mkdir and the write (e.g. a\n // concurrent output-directory clean); retry once.\n if (code === 'ENOENT' && attempt === 0) continue;\n\n throw error;\n }\n }\n\n return false;\n};\n\n/**\n * Rewrites the sentinel owned by this process, overwriting any existing file.\n */\nconst writeOwnedSentinel = async (\n sentinelFilePath: string,\n timestamp: number,\n status: SentinelStatus\n): Promise<void> => {\n try {\n await mkdir(dirname(sentinelFilePath), { recursive: true });\n await writeFile(sentinelFilePath, serializeSentinel(timestamp, status));\n } catch {}\n};\n\nconst removeSentinel = async (sentinelFilePath: string): Promise<void> => {\n try {\n await unlink(sentinelFilePath);\n } catch {}\n};\n\n/**\n * Ensures a callback function runs only once within a specified time window across multiple processes.\n * Uses a sentinel file to coordinate execution and prevent duplicate work.\n *\n * Processes that lose the race for the sentinel wait for the owner to finish\n * rather than running a competing copy of the callback — concurrent runs would\n * otherwise write to (and clean) the same output directory at the same time.\n *\n * @param sentinelFilePath - Path to the sentinel file used for coordination\n * @param callback - The function to execute (should be async)\n * @param options - The options for the runOnce function\n *\n * @example\n * ```typescript\n * await runOnce(\n * '/tmp/intlayer-sentinel',\n * async ({ renewLock }) => {\n * await cleanOutputDir(configuration); // may delete the sentinel\n * await renewLock();\n * await prepareIntlayer();\n * },\n * { cacheTimeoutMs: 30 * 1000 } // 30 seconds cache\n * );\n * ```\n *\n * @throws {Error} When there are unexpected filesystem errors\n */\nexport const runOnce = async (\n sentinelFilePath: string,\n callback: (context: RunOnceContext) => void | Promise<void>,\n options?: RunOnceOptions\n) => {\n const { onIsCached, cacheTimeoutMs, forceRun, lockWaitTimeoutMs } = {\n ...DEFAULT_RUN_ONCE_OPTIONS,\n ...(options ?? {}),\n };\n const currentTimestamp = Date.now();\n const waitDeadline = currentTimestamp + lockWaitTimeoutMs;\n\n // Acquisition loop: read the sentinel, then either return early (fresh cache),\n // wait for the current owner, or take the lock. Every branch either returns or\n // makes progress, so the loop always terminates.\n while (true) {\n const sentinelState = await readSentinelState(sentinelFilePath);\n\n if (sentinelState) {\n const sentinelAge = Date.now() - sentinelState.mtimeMs;\n\n if (sentinelState.status === 'running') {\n const isAbandoned =\n sentinelAge > lockWaitTimeoutMs ||\n !isOwnerProcessAlive(sentinelState.pid);\n\n if (!isAbandoned && Date.now() < waitDeadline) {\n await delay(LOCK_POLL_INTERVAL_MS);\n continue;\n }\n\n // The owner died or overran the timeout: reclaim the sentinel.\n await removeSentinel(sentinelFilePath);\n continue;\n }\n\n const isCacheValid =\n !forceRun &&\n sentinelAge <= cacheTimeoutMs &&\n sentinelState.version === packageJson.version;\n\n if (isCacheValid) {\n await onIsCached?.();\n return;\n }\n\n await removeSentinel(sentinelFilePath);\n }\n\n const hasAcquiredSentinel = await acquireSentinel(\n sentinelFilePath,\n currentTimestamp\n );\n\n if (hasAcquiredSentinel) break;\n\n // Another process won the race in the meantime: loop back and wait for it.\n // The delay also guarantees the loop yields, so a sentinel being repeatedly\n // created and removed can never turn into a busy wait.\n await delay(LOCK_POLL_INTERVAL_MS);\n }\n\n ownedSentinelFilePaths.add(sentinelFilePath);\n\n const renewLock = () =>\n writeOwnedSentinel(sentinelFilePath, currentTimestamp, 'running');\n\n try {\n await callback({ renewLock });\n\n // Mark the run as finished, re-creating the sentinel if the callback\n // deleted it (e.g. by cleaning the output directory).\n await writeOwnedSentinel(sentinelFilePath, currentTimestamp, 'done');\n } catch {\n await removeSentinel(sentinelFilePath); // Remove sentinel file if an error occurs\n } finally {\n ownedSentinelFilePaths.delete(sentinelFilePath);\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"runOnce.mjs","names":[],"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":["import { rmSync } from 'node:fs';\nimport { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport packageJson from '@intlayer/core/package.json' with { type: 'json' };\n\n/**\n * Lifecycle of the run described by a sentinel file.\n *\n * - `running` — a process owns the sentinel and its callback is still in flight.\n * Other processes must wait instead of starting a concurrent run.\n * - `done` — the callback completed; the sentinel is now a plain cache marker.\n */\ntype SentinelStatus = 'running' | 'done';\n\ntype SentinelData = {\n version: string;\n timestamp: number;\n status: SentinelStatus;\n /** PID of the process that owns the sentinel, used to detect abandoned locks. */\n pid: number;\n};\n\n/** Sentinel state as read from disk, enriched with the file's modification time. */\ntype SentinelState = SentinelData & { mtimeMs: number };\n\n/**\n * Context handed to the callback so it can interact with the lock it runs under.\n */\nexport type RunOnceContext = {\n /**\n * Re-create the sentinel file after an operation that may have deleted it —\n * typically cleaning the output directory, which wipes the cache directory the\n * sentinel lives in. Without this, concurrent processes would see no lock and\n * start a competing run while this one is still writing.\n */\n renewLock: () => Promise<void>;\n};\n\ntype RunOnceOptions = {\n /**\n * The function to execute when the sentinel is not found or is older than the cache timeout.\n */\n onIsCached?: () => void | Promise<void>;\n /**\n * The time window in milliseconds during which the sentinel is considered valid.\n *\n * @default 60000 = 1 minute\n */\n cacheTimeoutMs?: number;\n /**\n * If true, the callback will always run. If undefined, the callback will run only if the sentinel is older than the cache timeout.\n *\n * @default false\n */\n forceRun?: boolean;\n /**\n * How long to wait for another process to release the sentinel before\n * considering its run abandoned and taking the lock over.\n *\n * @default 300000 = 5 minutes\n */\n lockWaitTimeoutMs?: number;\n};\n\nconst DEFAULT_RUN_ONCE_OPTIONS = {\n cacheTimeoutMs: 60 * 1000, // 1 minute in milliseconds,\n lockWaitTimeoutMs: 5 * 60 * 1000, // 5 minutes in milliseconds\n} satisfies RunOnceOptions;\n\n/** Delay between two reads of a sentinel owned by another process. */\nconst LOCK_POLL_INTERVAL_MS = 50;\n\nconst delay = (durationMs: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, durationMs));\n\n/**\n * Sentinels owned by this process, released synchronously on exit so a crash or\n * a Ctrl-C never leaves a `running` lock that would stall the next run.\n */\nconst ownedSentinelFilePaths = new Set<string>();\n\nprocess.on('exit', () => {\n for (const sentinelFilePath of ownedSentinelFilePaths) {\n try {\n rmSync(sentinelFilePath, { force: true });\n } catch {}\n }\n});\n\n/**\n * Reads the sentinel file, returning `undefined` when it does not exist or\n * cannot be parsed.\n *\n * Sentinels written by older versions carry no `status`; they always describe a\n * finished run, so they are reported as `done`.\n */\nconst readSentinelState = async (\n sentinelFilePath: string\n): Promise<SentinelState | undefined> => {\n try {\n const [sentinelStats, raw] = await Promise.all([\n stat(sentinelFilePath),\n readFile(sentinelFilePath, 'utf8'),\n ]);\n\n const parsed = JSON.parse(raw) as Partial<SentinelData>;\n\n return {\n version: parsed.version ?? '',\n timestamp: parsed.timestamp ?? 0,\n status: parsed.status ?? 'done',\n pid: parsed.pid ?? 0,\n mtimeMs: sentinelStats.mtime.getTime(),\n };\n } catch {\n return undefined;\n }\n};\n\n/**\n * Whether the process that wrote the sentinel is still alive. An unknown PID\n * (legacy sentinel) is assumed alive so the staleness timeout stays the only\n * way to reclaim it.\n */\nconst isOwnerProcessAlive = (pid: number): boolean => {\n if (!pid || pid === process.pid) return true;\n\n try {\n // Signal 0 performs an existence check without delivering a signal.\n process.kill(pid, 0);\n return true;\n } catch (error) {\n // EPERM means the process exists but belongs to another user.\n return (error as NodeJS.ErrnoException).code === 'EPERM';\n }\n};\n\nconst serializeSentinel = (timestamp: number, status: SentinelStatus): string =>\n JSON.stringify({\n version: packageJson.version,\n timestamp,\n status,\n pid: process.pid,\n } satisfies SentinelData);\n\n/**\n * Attempts to take ownership of the sentinel.\n *\n * `wx` makes the creation atomic, so exactly one process can win even when\n * several start at the same moment.\n *\n * @returns `true` when this process now owns the sentinel, `false` when another\n * process created it first.\n */\nconst acquireSentinel = async (\n sentinelFilePath: string,\n timestamp: number\n): Promise<boolean> => {\n const data = serializeSentinel(timestamp, 'running');\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n // Ensure the directory exists before writing the file\n await mkdir(dirname(sentinelFilePath), { recursive: true });\n\n await writeFile(sentinelFilePath, data, { flag: 'wx' });\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n\n if (code === 'EEXIST') return false;\n // The directory was removed between the mkdir and the write (e.g. a\n // concurrent output-directory clean); retry once.\n if (code === 'ENOENT' && attempt === 0) continue;\n\n throw error;\n }\n }\n\n return false;\n};\n\n/**\n * Rewrites the sentinel owned by this process, overwriting any existing file.\n */\nconst writeOwnedSentinel = async (\n sentinelFilePath: string,\n timestamp: number,\n status: SentinelStatus\n): Promise<void> => {\n try {\n await mkdir(dirname(sentinelFilePath), { recursive: true });\n await writeFile(sentinelFilePath, serializeSentinel(timestamp, status));\n } catch {}\n};\n\nconst removeSentinel = async (sentinelFilePath: string): Promise<void> => {\n try {\n await unlink(sentinelFilePath);\n } catch {}\n};\n\n/**\n * Ensures a callback function runs only once within a specified time window across multiple processes.\n * Uses a sentinel file to coordinate execution and prevent duplicate work.\n *\n * Processes that lose the race for the sentinel wait for the owner to finish\n * rather than running a competing copy of the callback — concurrent runs would\n * otherwise write to (and clean) the same output directory at the same time.\n *\n * @param sentinelFilePath - Path to the sentinel file used for coordination\n * @param callback - The function to execute (should be async)\n * @param options - The options for the runOnce function\n *\n * @example\n * ```typescript\n * await runOnce(\n * '/tmp/intlayer-sentinel',\n * async ({ renewLock }) => {\n * await cleanOutputDir(configuration); // may delete the sentinel\n * await renewLock();\n * await prepareIntlayer();\n * },\n * { cacheTimeoutMs: 30 * 1000 } // 30 seconds cache\n * );\n * ```\n *\n * @throws {Error} When there are unexpected filesystem errors\n */\nexport const runOnce = async (\n sentinelFilePath: string,\n callback: (context: RunOnceContext) => void | Promise<void>,\n options?: RunOnceOptions\n) => {\n const { onIsCached, cacheTimeoutMs, forceRun, lockWaitTimeoutMs } = {\n ...DEFAULT_RUN_ONCE_OPTIONS,\n ...(options ?? {}),\n };\n const currentTimestamp = Date.now();\n const waitDeadline = currentTimestamp + lockWaitTimeoutMs;\n\n // Acquisition loop: read the sentinel, then either return early (fresh cache),\n // wait for the current owner, or take the lock. Every branch either returns or\n // makes progress, so the loop always terminates.\n while (true) {\n const sentinelState = await readSentinelState(sentinelFilePath);\n\n if (sentinelState) {\n const sentinelAge = Date.now() - sentinelState.mtimeMs;\n\n if (sentinelState.status === 'running') {\n const isAbandoned =\n sentinelAge > lockWaitTimeoutMs ||\n !isOwnerProcessAlive(sentinelState.pid);\n\n if (!isAbandoned && Date.now() < waitDeadline) {\n await delay(LOCK_POLL_INTERVAL_MS);\n continue;\n }\n\n // The owner died or overran the timeout: reclaim the sentinel.\n await removeSentinel(sentinelFilePath);\n continue;\n }\n\n const isCacheValid =\n !forceRun &&\n sentinelAge <= cacheTimeoutMs &&\n sentinelState.version === packageJson.version;\n\n if (isCacheValid) {\n await onIsCached?.();\n return;\n }\n\n await removeSentinel(sentinelFilePath);\n }\n\n const hasAcquiredSentinel = await acquireSentinel(\n sentinelFilePath,\n currentTimestamp\n );\n\n if (hasAcquiredSentinel) break;\n\n // Another process won the race in the meantime: loop back and wait for it.\n // The delay also guarantees the loop yields, so a sentinel being repeatedly\n // created and removed can never turn into a busy wait.\n await delay(LOCK_POLL_INTERVAL_MS);\n }\n\n ownedSentinelFilePaths.add(sentinelFilePath);\n\n const renewLock = () =>\n writeOwnedSentinel(sentinelFilePath, currentTimestamp, 'running');\n\n try {\n await callback({ renewLock });\n\n // Mark the run as finished, re-creating the sentinel if the callback\n // deleted it (e.g. by cleaning the output directory).\n await writeOwnedSentinel(sentinelFilePath, currentTimestamp, 'done');\n } catch {\n await removeSentinel(sentinelFilePath); // Remove sentinel file if an error occurs\n } finally {\n ownedSentinelFilePaths.delete(sentinelFilePath);\n }\n};\n"],"mappings":"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"}
@@ -81,7 +81,8 @@ const watch = async (options) => {
81
81
  if (rel.endsWith(".tmp")) continue;
82
82
  if (event.type === "update") processEvent(async () => {
83
83
  try {
84
- await transpileTSToCJS(await readFile(event.path, "utf-8"), event.path);
84
+ const entryCode = await readFile(event.path, "utf-8");
85
+ await transpileTSToCJS(entryCode, event.path);
85
86
  } catch {
86
87
  appLogger(`Entry point ${basename(event.path)} failed to load, running clean rebuild...`, { level: "warn" });
87
88
  await prepareIntlayer(configuration, {
@@ -166,8 +167,9 @@ const watch = async (options) => {
166
167
  processEvent(async () => {
167
168
  if (await readFile(filePath, "utf-8") === "") {
168
169
  const extensionPattern = fileExtensions.map((ext) => ext.replace(/\./g, "\\.")).join("|");
170
+ const name = fileName.replace(new RegExp(`(${extensionPattern})$`), "");
169
171
  await writeContentDeclaration({
170
- key: fileName.replace(new RegExp(`(${extensionPattern})$`), ""),
172
+ key: name,
171
173
  content: {},
172
174
  filePath
173
175
  }, configuration);
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.mjs","names":["fsWatch"],"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.mjs","names":["fsWatch"],"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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"}
@@ -6,7 +6,8 @@ import { join } from "node:path";
6
6
  //#region src/writeConfiguration/index.ts
7
7
  const isCachedConfigurationUpToDate = async (configuration) => {
8
8
  try {
9
- return await readFile(join(configuration.system.configDir, "configuration.mjs"), "utf8") === generateConfigurationContent(configuration, "esm");
9
+ const mjsPath = join(configuration.system.configDir, "configuration.mjs");
10
+ return await readFile(mjsPath, "utf8") === generateConfigurationContent(configuration, "esm");
10
11
  } catch {
11
12
  return null;
12
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"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;EAIF,OAAO,MAFuB,SADd,KAAK,cAAc,OAAO,WAAW,mBACR,GAAG,MAAM,MAC9B,6BAA6B,eAAe,KAC3B;CAC3C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,qBAAqB,OAAO,kBAAkC;CACzE,MAAM,EAAE,cAAc,cAAc;CAEpC,MAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;CAE1C,MAAM,QAAQ,IAAI,CAChB,mBACE,KAAK,WAAW,mBAAmB,GACnC,6BAA6B,eAAe,KAAK,CACnD,GACA,mBACE,KAAK,WAAW,mBAAmB,GACnC,6BAA6B,eAAe,KAAK,CACnD,CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.mjs","names":[],"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,UAAU,KAAK,cAAc,OAAO,WAAW,mBAAmB;EAGxE,OAAO,MAFuB,SAAS,SAAS,MAAM,MAC9B,6BAA6B,eAAe,KAC3B;CAC3C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,qBAAqB,OAAO,kBAAkC;CACzE,MAAM,EAAE,cAAc,cAAc;CAEpC,MAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;CAE1C,MAAM,QAAQ,IAAI,CAChB,mBACE,KAAK,WAAW,mBAAmB,GACnC,6BAA6B,eAAe,KAAK,CACnD,GACA,mBACE,KAAK,WAAW,mBAAmB,GACnC,6BAA6B,eAAe,KAAK,CACnD,CACF,CAAC;AACH"}
@@ -236,19 +236,21 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
236
236
  }, true)], []);
237
237
  return b.literal(val);
238
238
  }
239
- if (Array.isArray(val)) if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {
240
- const elements = [...unwrappedExisting.elements];
241
- val.forEach((item, i) => {
242
- const elementNode = buildNodeForValue(item, elements[i], fallbackLocale, requiredImports);
243
- elements[i] = elementNode === SKIP_WRITE ? elements[i] ?? b.literal(null) : elementNode;
244
- });
245
- if (elements.length > val.length) elements.length = val.length;
246
- unwrappedExisting.elements = elements;
247
- return existingNode;
248
- } else return b.arrayExpression(val.map((item) => {
249
- const elementNode = buildNodeForValue(item, null, fallbackLocale, requiredImports);
250
- return elementNode === SKIP_WRITE ? b.literal(null) : elementNode;
251
- }));
239
+ if (Array.isArray(val)) {
240
+ if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {
241
+ const elements = [...unwrappedExisting.elements];
242
+ val.forEach((item, i) => {
243
+ const elementNode = buildNodeForValue(item, elements[i], fallbackLocale, requiredImports);
244
+ elements[i] = elementNode === SKIP_WRITE ? elements[i] ?? b.literal(null) : elementNode;
245
+ });
246
+ if (elements.length > val.length) elements.length = val.length;
247
+ unwrappedExisting.elements = elements;
248
+ return existingNode;
249
+ } else return b.arrayExpression(val.map((item) => {
250
+ const elementNode = buildNodeForValue(item, null, fallbackLocale, requiredImports);
251
+ return elementNode === SKIP_WRITE ? b.literal(null) : elementNode;
252
+ }));
253
+ }
252
254
  const nodeType = val && typeof val === "object" && !Array.isArray(val) ? getNodeType(val) : null;
253
255
  if (nodeType) {
254
256
  const strategy = nodeTypeStrategies[nodeType];
@@ -349,17 +351,18 @@ const addImports = (ast, requiredImports, isESM) => {
349
351
  });
350
352
  const missingCore = Array.from(requiredImports).filter((imp) => !existingCoreImports.has(imp));
351
353
  if (missingCore.length === 0) return;
352
- if (isESM) if (coreImportPath) {
353
- missingCore.forEach((imp) => {
354
- coreImportPath.node.specifiers.push(b.importSpecifier(b.identifier(imp)));
355
- });
356
- coreImportPath.node.specifiers.sort((a, b) => a.imported.name.localeCompare(b.imported.name));
354
+ if (isESM) {
355
+ if (coreImportPath) {
356
+ missingCore.forEach((imp) => {
357
+ coreImportPath.node.specifiers.push(b.importSpecifier(b.identifier(imp)));
358
+ });
359
+ coreImportPath.node.specifiers.sort((a, b) => a.imported.name.localeCompare(b.imported.name));
360
+ } else {
361
+ const specifiers = missingCore.sort().map((imp) => b.importSpecifier(b.identifier(imp)));
362
+ const newImport = b.importDeclaration(specifiers, b.literal("intlayer"));
363
+ ast.program.body.unshift(newImport);
364
+ }
357
365
  } else {
358
- const specifiers = missingCore.sort().map((imp) => b.importSpecifier(b.identifier(imp)));
359
- const newImport = b.importDeclaration(specifiers, b.literal("intlayer"));
360
- ast.program.body.unshift(newImport);
361
- }
362
- else {
363
366
  let insertIndex = 0;
364
367
  if (ast.program.body.length > 0 && n.ExpressionStatement.check(ast.program.body[0]) && n.Literal.check(ast.program.body[0].expression)) insertIndex = 1;
365
368
  const cjsLines = [];
@@ -1 +1 @@
1
- {"version":3,"file":"transformJSFile.mjs","names":[],"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.mjs","names":[],"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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"}
@@ -57,11 +57,12 @@ const updateObjectLiteral = (node, data) => {
57
57
  c.trailing = true;
58
58
  }
59
59
  });
60
- if (isPlainObject(val)) if (existingProp && n.ObjectExpression.check(existingProp.value)) updateObjectLiteral(existingProp.value, val);
61
- else if (existingProp) {
62
- if (!(n.Literal.check(existingProp.value) && existingProp.value.value === val)) existingProp.value = buildASTNode(val);
63
- } else node.properties.push(b.property("init", b.stringLiteral(key), buildASTNode(val)));
64
- else if (existingProp) {
60
+ if (isPlainObject(val)) {
61
+ if (existingProp && n.ObjectExpression.check(existingProp.value)) updateObjectLiteral(existingProp.value, val);
62
+ else if (existingProp) {
63
+ if (!(n.Literal.check(existingProp.value) && existingProp.value.value === val)) existingProp.value = buildASTNode(val);
64
+ } else node.properties.push(b.property("init", b.stringLiteral(key), buildASTNode(val)));
65
+ } else if (existingProp) {
65
66
  if (!isPrimitiveEqual(existingProp.value, val)) existingProp.value = buildASTNode(val);
66
67
  } else node.properties.push(b.property("init", b.stringLiteral(key), buildASTNode(val)));
67
68
  }