@intlayer/engine 9.2.0 → 9.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) 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 +14 -2
  8. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  9. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +26 -5
  10. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
  11. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs +43 -6
  12. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
  13. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -1
  14. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
  15. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs +96 -0
  16. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -0
  17. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +4 -2
  18. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
  19. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
  20. package/dist/cjs/cleanOutputDir.cjs.map +1 -1
  21. package/dist/cjs/cleanRemovedContentDeclaration.cjs +7 -4
  22. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  23. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +5 -3
  24. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
  25. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
  26. package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
  27. package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
  28. package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
  29. package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
  30. package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
  31. package/dist/cjs/createType/createModuleAugmentation.cjs +2 -1
  32. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  33. package/dist/cjs/createType/createType.cjs.map +1 -1
  34. package/dist/cjs/detectFormatCommand.cjs.map +1 -1
  35. package/dist/cjs/docReview/alignBlocks.cjs +1 -1
  36. package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
  37. package/dist/cjs/docReview/computeSimilarity.cjs +0 -1
  38. package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
  39. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +0 -1
  40. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
  41. package/dist/cjs/docReview/normalizeBlock.cjs +0 -1
  42. package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
  43. package/dist/cjs/docReview/planActions.cjs +0 -1
  44. package/dist/cjs/docReview/planActions.cjs.map +1 -1
  45. package/dist/cjs/docReview/rebuildDocument.cjs +0 -1
  46. package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
  47. package/dist/cjs/docReview/reviewReport.cjs +2 -1
  48. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  49. package/dist/cjs/docReview/segmentDocument.cjs +0 -1
  50. package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
  51. package/dist/cjs/fetchDistantDictionaries.cjs +107 -13
  52. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  53. package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
  54. package/dist/cjs/formatDictionary.cjs.map +1 -1
  55. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
  56. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +4 -2
  57. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
  58. package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -2
  59. package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
  60. package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
  61. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +4 -2
  62. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
  63. package/dist/cjs/init/cms.cjs.map +1 -1
  64. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
  65. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +1 -3
  66. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  67. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +2 -1
  68. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
  69. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +0 -1
  70. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
  71. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
  72. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +3 -5
  73. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  74. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -1
  75. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
  76. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +18 -12
  77. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
  78. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +58 -15
  79. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  80. package/dist/cjs/init/index.cjs +66 -38
  81. package/dist/cjs/init/index.cjs.map +1 -1
  82. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  83. package/dist/cjs/init/utils/fileSystem.cjs +3 -1
  84. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  85. package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
  86. package/dist/cjs/init/utils/jsonParser.cjs +0 -1
  87. package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
  88. package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
  89. package/dist/cjs/init/utils/packageManager.cjs +4 -2
  90. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  91. package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
  92. package/dist/cjs/init/utils/version.cjs +0 -1
  93. package/dist/cjs/init/utils/version.cjs.map +1 -1
  94. package/dist/cjs/initConfig/index.cjs +12 -8
  95. package/dist/cjs/initConfig/index.cjs.map +1 -1
  96. package/dist/cjs/installSkills/index.cjs.map +1 -1
  97. package/dist/cjs/listDictionariesPath.cjs +6 -5
  98. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  99. package/dist/cjs/listGitFiles.cjs.map +1 -1
  100. package/dist/cjs/listProjects.cjs +2 -1
  101. package/dist/cjs/listProjects.cjs.map +1 -1
  102. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +2 -1
  103. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
  104. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +8 -5
  105. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  106. package/dist/cjs/loadDictionaries/loadDictionaries.cjs +4 -2
  107. package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
  108. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
  109. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
  110. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +3 -2
  111. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  112. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +2 -1
  113. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
  114. package/dist/cjs/loadDictionaries/log.cjs +38 -11
  115. package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
  116. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  117. package/dist/cjs/logConfigDetails.cjs +4 -3
  118. package/dist/cjs/logConfigDetails.cjs.map +1 -1
  119. package/dist/cjs/prepareIntlayer.cjs +5 -3
  120. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  121. package/dist/cjs/reduceDictionaryContent/applyMask.cjs +0 -1
  122. package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
  123. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +2 -1
  124. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
  125. package/dist/cjs/scan/calculateScore.cjs +0 -1
  126. package/dist/cjs/scan/calculateScore.cjs.map +1 -1
  127. package/dist/cjs/scan/checks.cjs +1 -1
  128. package/dist/cjs/scan/checks.cjs.map +1 -1
  129. package/dist/cjs/scan/parseHtml.cjs +0 -1
  130. package/dist/cjs/scan/parseHtml.cjs.map +1 -1
  131. package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
  132. package/dist/cjs/syncPluginKit/createFileAdapter.cjs +2 -1
  133. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
  134. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +4 -1
  135. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
  136. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +0 -1
  137. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
  138. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +0 -1
  139. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
  140. package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
  141. package/dist/cjs/utils/babelParser.cjs.map +1 -1
  142. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  143. package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
  144. package/dist/cjs/utils/chunkArray.cjs +23 -0
  145. package/dist/cjs/utils/chunkArray.cjs.map +1 -0
  146. package/dist/cjs/utils/formatter.cjs.map +1 -1
  147. package/dist/cjs/utils/getContentExtension.cjs +1 -4
  148. package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
  149. package/dist/cjs/utils/getFormatFromExtension.cjs +0 -1
  150. package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
  151. package/dist/cjs/utils/getPathHash.cjs +0 -1
  152. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  153. package/dist/cjs/utils/index.cjs +2 -0
  154. package/dist/cjs/utils/mergeChunks.cjs +0 -1
  155. package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
  156. package/dist/cjs/utils/pLimit.cjs +0 -1
  157. package/dist/cjs/utils/pLimit.cjs.map +1 -1
  158. package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
  159. package/dist/cjs/utils/reduceObjectFormat.cjs +0 -1
  160. package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
  161. package/dist/cjs/utils/resolveObjectPromises.cjs +0 -1
  162. package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
  163. package/dist/cjs/utils/resolveRelativePath.cjs +4 -1
  164. package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
  165. package/dist/cjs/utils/runOnce.cjs +2 -2
  166. package/dist/cjs/utils/runOnce.cjs.map +1 -1
  167. package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
  168. package/dist/cjs/utils/runParallel/bootstrap.cjs +0 -1
  169. package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
  170. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  171. package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
  172. package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
  173. package/dist/cjs/utils/sortAlphabetically.cjs +0 -1
  174. package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
  175. package/dist/cjs/utils/splitTextByLine.cjs +0 -1
  176. package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
  177. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs +0 -1
  178. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
  179. package/dist/cjs/watcher.cjs +4 -2
  180. package/dist/cjs/watcher.cjs.map +1 -1
  181. package/dist/cjs/writeConfiguration/index.cjs +2 -1
  182. package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
  183. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +0 -1
  184. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
  185. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
  186. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +173 -109
  187. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
  188. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs +6 -5
  189. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
  190. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +9 -3
  191. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  192. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +2 -1
  193. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
  194. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -1
  195. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  196. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +4 -2
  197. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  198. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  199. package/dist/esm/_virtual/_utils_asset.mjs +2 -1
  200. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs +15 -3
  201. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs.map +1 -1
  202. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +26 -5
  203. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
  204. package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs +43 -6
  205. package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs.map +1 -1
  206. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
  207. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
  208. package/dist/esm/buildIntlayerDictionary/writeNestedDictionary.mjs +92 -0
  209. package/dist/esm/buildIntlayerDictionary/writeNestedDictionary.mjs.map +1 -0
  210. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +4 -2
  211. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
  212. package/dist/esm/cleanRemovedContentDeclaration.mjs +7 -4
  213. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  214. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs +5 -3
  215. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
  216. package/dist/esm/createType/createModuleAugmentation.mjs +2 -1
  217. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  218. package/dist/esm/docReview/alignBlocks.mjs +1 -1
  219. package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
  220. package/dist/esm/docReview/reviewReport.mjs +2 -1
  221. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  222. package/dist/esm/fetchDistantDictionaries.mjs +107 -13
  223. package/dist/esm/fetchDistantDictionaries.mjs.map +1 -1
  224. package/dist/esm/handleAdditionalContentDeclarationFile.mjs +4 -2
  225. package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
  226. package/dist/esm/handleContentDeclarationFileChange.mjs +6 -2
  227. package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
  228. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +4 -2
  229. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
  230. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +1 -3
  231. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  232. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +2 -1
  233. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
  234. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +4 -6
  235. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  236. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -1
  237. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
  238. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +17 -10
  239. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
  240. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +59 -16
  241. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  242. package/dist/esm/init/index.mjs +66 -38
  243. package/dist/esm/init/index.mjs.map +1 -1
  244. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  245. package/dist/esm/init/utils/fileSystem.mjs +3 -1
  246. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  247. package/dist/esm/init/utils/packageManager.mjs +4 -2
  248. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  249. package/dist/esm/initConfig/index.mjs +12 -8
  250. package/dist/esm/initConfig/index.mjs.map +1 -1
  251. package/dist/esm/listDictionariesPath.mjs +6 -5
  252. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  253. package/dist/esm/listProjects.mjs +2 -1
  254. package/dist/esm/listProjects.mjs.map +1 -1
  255. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs +2 -1
  256. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
  257. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +8 -5
  258. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  259. package/dist/esm/loadDictionaries/loadDictionaries.mjs +4 -2
  260. package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
  261. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +3 -2
  262. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
  263. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs +2 -1
  264. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
  265. package/dist/esm/loadDictionaries/log.mjs +38 -11
  266. package/dist/esm/loadDictionaries/log.mjs.map +1 -1
  267. package/dist/esm/logConfigDetails.mjs +4 -3
  268. package/dist/esm/logConfigDetails.mjs.map +1 -1
  269. package/dist/esm/prepareIntlayer.mjs +5 -3
  270. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  271. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs +2 -1
  272. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
  273. package/dist/esm/scan/checks.mjs +1 -1
  274. package/dist/esm/scan/checks.mjs.map +1 -1
  275. package/dist/esm/syncPluginKit/createFileAdapter.mjs +2 -1
  276. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
  277. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +4 -1
  278. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
  279. package/dist/esm/utils/babelParser.mjs.map +1 -1
  280. package/dist/esm/utils/chunkArray.mjs +22 -0
  281. package/dist/esm/utils/chunkArray.mjs.map +1 -0
  282. package/dist/esm/utils/getContentExtension.mjs +1 -3
  283. package/dist/esm/utils/getContentExtension.mjs.map +1 -1
  284. package/dist/esm/utils/index.mjs +2 -1
  285. package/dist/esm/utils/resolveRelativePath.mjs +4 -1
  286. package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
  287. package/dist/esm/utils/runOnce.mjs +2 -2
  288. package/dist/esm/utils/runOnce.mjs.map +1 -1
  289. package/dist/esm/watcher.mjs +4 -2
  290. package/dist/esm/watcher.mjs.map +1 -1
  291. package/dist/esm/writeConfiguration/index.mjs +2 -1
  292. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  293. package/dist/esm/writeContentDeclaration/transformJSFile.mjs +173 -109
  294. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  295. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs +6 -5
  296. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
  297. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +9 -3
  298. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  299. package/dist/esm/writeContentDeclaration/writeJSFile.mjs +2 -1
  300. package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
  301. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -1
  302. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  303. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +4 -2
  304. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  305. package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts.map +1 -1
  306. package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts +14 -2
  307. package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts.map +1 -1
  308. package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts +16 -2
  309. package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts.map +1 -1
  310. package/dist/types/buildIntlayerDictionary/writeNestedDictionary.d.ts +54 -0
  311. package/dist/types/buildIntlayerDictionary/writeNestedDictionary.d.ts.map +1 -0
  312. package/dist/types/fetchDistantDictionaries.d.ts +26 -0
  313. package/dist/types/fetchDistantDictionaries.d.ts.map +1 -1
  314. package/dist/types/formatDictionary.d.ts +2 -0
  315. package/dist/types/formatDictionary.d.ts.map +1 -1
  316. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +9 -4
  317. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  318. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +6 -2
  319. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  320. package/dist/types/loadDictionaries/log.d.ts +16 -1
  321. package/dist/types/loadDictionaries/log.d.ts.map +1 -1
  322. package/dist/types/utils/chunkArray.d.ts +16 -0
  323. package/dist/types/utils/chunkArray.d.ts.map +1 -0
  324. package/dist/types/utils/index.d.ts +2 -1
  325. package/dist/types/writeContentDeclaration/transformJSFile.d.ts.map +1 -1
  326. package/package.json +11 -11
@@ -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"}
@@ -7,6 +7,81 @@ import * as recast from "recast";
7
7
  const b = recast.types.builders;
8
8
  const n = recast.types.namedTypes;
9
9
  /**
10
+ * Every {@link NodeType} and how it is written back to a JS/TS declaration file.
11
+ *
12
+ * Typed as `Record<NodeType, NodeTypeStrategy>` so that adding a node type to
13
+ * `@intlayer/types` without registering it here becomes a compile-time error —
14
+ * the same guarantee `getNodeType` gives on the read side.
15
+ */
16
+ const nodeTypeStrategies = {
17
+ [NodeTypes.TRANSLATION]: {
18
+ kind: "helperRecord",
19
+ helper: "t"
20
+ },
21
+ [NodeTypes.ENUMERATION]: {
22
+ kind: "helperRecord",
23
+ helper: "enu"
24
+ },
25
+ [NodeTypes.PLURAL]: {
26
+ kind: "helperRecord",
27
+ helper: "plural"
28
+ },
29
+ [NodeTypes.CONDITION]: {
30
+ kind: "helperRecord",
31
+ helper: "cond"
32
+ },
33
+ [NodeTypes.GENDER]: {
34
+ kind: "helperRecord",
35
+ helper: "gender"
36
+ },
37
+ [NodeTypes.SELECT]: {
38
+ kind: "helperRecord",
39
+ helper: "select",
40
+ getExtraArguments: (node) => typeof node.variable === "string" && node.variable.length > 0 ? [b.literal(node.variable)] : []
41
+ },
42
+ [NodeTypes.INSERTION]: {
43
+ kind: "helperValue",
44
+ helper: "insert"
45
+ },
46
+ [NodeTypes.MARKDOWN]: {
47
+ kind: "helperValue",
48
+ helper: "md"
49
+ },
50
+ [NodeTypes.HTML]: {
51
+ kind: "helperValue",
52
+ helper: "html"
53
+ },
54
+ [NodeTypes.FILE]: {
55
+ kind: "helperValue",
56
+ helper: "file"
57
+ },
58
+ [NodeTypes.NESTED]: {
59
+ kind: "nesting",
60
+ helper: "nest"
61
+ },
62
+ [NodeTypes.TEXT]: { kind: "unwrap" },
63
+ [NodeTypes.NUMBER]: { kind: "unwrap" },
64
+ [NodeTypes.BOOLEAN]: { kind: "unwrap" },
65
+ [NodeTypes.NULL]: { kind: "unwrap" },
66
+ [NodeTypes.REACT_NODE]: { kind: "preserve" },
67
+ [NodeTypes.PREACT_NODE]: { kind: "preserve" },
68
+ [NodeTypes.SOLID_NODE]: { kind: "preserve" },
69
+ [NodeTypes.OBJECT]: { kind: "structural" },
70
+ [NodeTypes.ARRAY]: { kind: "structural" },
71
+ [NodeTypes.UNKNOWN]: { kind: "structural" }
72
+ };
73
+ /** Every `intlayer` helper the transform is allowed to rewrite. */
74
+ const helperNames = new Set(Object.values(nodeTypeStrategies).flatMap((strategy) => "helper" in strategy ? [strategy.helper] : []));
75
+ /** Helpers wrapping a single content, e.g. `md(t({ … }))`. */
76
+ const wrapperHelperNames = new Set(Object.values(nodeTypeStrategies).flatMap((strategy) => strategy.kind === "helperValue" ? [strategy.helper] : []));
77
+ /**
78
+ * Returned by {@link buildNodeForValue} when a value must not be written to the
79
+ * source file — framework elements and functions have no data representation,
80
+ * so the original expression (when there is one) is left untouched and no new
81
+ * property is created otherwise.
82
+ */
83
+ const SKIP_WRITE = Symbol("intlayer.skipWrite");
84
+ /**
10
85
  * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).
11
86
  * Uses string fallbacks to bypass outdated ast-types definitions.
12
87
  */
@@ -61,39 +136,51 @@ const syncNumericSuffixAcrossLocales = (existingNode, fallbackLocaleCode, newFal
61
136
  };
62
137
  /**
63
138
  * Checks if a value represents a multilingual Intlayer node.
64
- * A node is multilingual if it is a Translation node, or if it is a specialized node
65
- * (Markdown, HTML, etc.) that contains a Translation node.
139
+ *
140
+ * A node is multilingual if it is a Translation node, if it wraps one
141
+ * (Markdown, HTML, Insertion…), or if any of its variants contains one
142
+ * (Enumeration, Plural, Condition, Gender, Select…).
66
143
  */
67
144
  const isMultilingualNode = (val) => {
68
145
  if (typeof val !== "object" || val === null || Array.isArray(val)) return false;
69
146
  const nodeType = getNodeType(val);
70
147
  if (nodeType === NodeTypes.TRANSLATION) return true;
71
- if (nodeType === NodeTypes.MARKDOWN || nodeType === NodeTypes.HTML || nodeType === NodeTypes.INSERTION) return isMultilingualNode(val[nodeType]);
72
- if (nodeType === NodeTypes.ENUMERATION || nodeType === NodeTypes.PLURAL || nodeType === NodeTypes.CONDITION || nodeType === NodeTypes.GENDER || nodeType === NodeTypes.SELECT) {
73
- const data = val[nodeType];
74
- if (data && typeof data === "object") return Object.values(data).some((v) => isMultilingualNode(v));
75
- }
148
+ const strategy = nodeTypeStrategies[nodeType];
149
+ const nodeData = val[nodeType];
150
+ if (strategy.kind === "helperValue" || strategy.kind === "unwrap") return isMultilingualNode(nodeData);
151
+ if (strategy.kind === "helperRecord" && nodeData && typeof nodeData === "object") return Object.values(nodeData).some((variant) => isMultilingualNode(variant));
76
152
  return false;
77
153
  };
78
154
  /**
155
+ * Checks whether two AST nodes are literals holding the same value.
156
+ */
157
+ const isEquivalentLiteral = (left, right) => {
158
+ const isLiteral = (node) => n.Literal.check(node) || n.StringLiteral.check(node) || n.NumericLiteral.check(node) || n.BooleanLiteral.check(node);
159
+ return isLiteral(left) && isLiteral(right) && left.value === right.value;
160
+ };
161
+ /**
162
+ * Aligns the arguments of an existing call expression with the desired ones.
163
+ *
164
+ * Mutates the call only when the arguments actually differ, so Recast keeps the
165
+ * original formatting (and quote style) of calls that did not change.
166
+ */
167
+ const syncCallArguments = (callNode, desiredArguments) => {
168
+ if (!(callNode.arguments.length === desiredArguments.length && desiredArguments.every((desired, index) => {
169
+ const current = callNode.arguments[index];
170
+ return current === desired || isEquivalentLiteral(current, desired);
171
+ }))) callNode.arguments = desiredArguments;
172
+ };
173
+ /**
79
174
  * Recursively builds or updates an AST node for a given dictionary value.
175
+ *
176
+ * Returns {@link SKIP_WRITE} when the value cannot be represented in source and
177
+ * no existing expression can be kept.
80
178
  */
81
179
  const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) => {
180
+ if (val === void 0 || typeof val === "function") return existingNode ?? SKIP_WRITE;
82
181
  const unwrappedExisting = unwrap(existingNode);
83
182
  if (unwrappedExisting) {
84
- if (!(n.Literal.check(unwrappedExisting) || n.StringLiteral.check(unwrappedExisting) || n.NumericLiteral.check(unwrappedExisting) || n.BooleanLiteral.check(unwrappedExisting) || n.TemplateLiteral.check(unwrappedExisting) || n.ObjectExpression.check(unwrappedExisting) || n.ArrayExpression.check(unwrappedExisting) || n.CallExpression.check(unwrappedExisting) && n.Identifier.check(unwrappedExisting.callee) && [
85
- "t",
86
- "enu",
87
- "plural",
88
- "cond",
89
- "gender",
90
- "select",
91
- "insert",
92
- "md",
93
- "html",
94
- "file",
95
- "nest"
96
- ].includes(unwrappedExisting.callee.name))) return existingNode;
183
+ if (!(n.Literal.check(unwrappedExisting) || n.StringLiteral.check(unwrappedExisting) || n.NumericLiteral.check(unwrappedExisting) || n.BooleanLiteral.check(unwrappedExisting) || n.TemplateLiteral.check(unwrappedExisting) || n.ObjectExpression.check(unwrappedExisting) || n.ArrayExpression.check(unwrappedExisting) || n.CallExpression.check(unwrappedExisting) && n.Identifier.check(unwrappedExisting.callee) && helperNames.has(unwrappedExisting.callee.name))) return existingNode;
97
184
  }
98
185
  if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {
99
186
  if (val === null) return b.literal(null);
@@ -115,14 +202,15 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
115
202
  return existingNode;
116
203
  }
117
204
  }
118
- if ((!val || typeof val !== "object") && n.CallExpression.check(existingNode) && n.Identifier.check(existingNode.callee) && existingNode.callee.name === "md") {
205
+ if ((!val || typeof val !== "object") && n.CallExpression.check(existingNode) && n.Identifier.check(existingNode.callee) && wrapperHelperNames.has(existingNode.callee.name)) {
206
+ const wrapperName = existingNode.callee.name;
119
207
  const innerArg = existingNode.arguments[0];
120
208
  if (n.CallExpression.check(innerArg) && n.Identifier.check(innerArg.callee) && innerArg.callee.name === "t") {
121
209
  const tArg = unwrap(innerArg.arguments[0]);
122
210
  if (n.ObjectExpression.check(tArg)) {
123
211
  if (typeof val === "string") syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);
124
212
  updateObjectLiteral(tArg, { [fallbackLocale]: val }, fallbackLocale, requiredImports);
125
- requiredImports.add("md");
213
+ requiredImports.add(wrapperName);
126
214
  requiredImports.add("t");
127
215
  return existingNode;
128
216
  }
@@ -132,7 +220,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
132
220
  if (val === null) return b.literal(null);
133
221
  if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
134
222
  if (unwrappedExisting) {
135
- if (n.TemplateLiteral.check(unwrappedExisting) && unwrappedExisting.expressions.length === 0) {
223
+ if (n.TemplateLiteral.check(unwrappedExisting) && unwrappedExisting.quasis[0] && unwrappedExisting.expressions.length === 0) {
136
224
  unwrappedExisting.quasis[0].value.raw = String(val);
137
225
  unwrappedExisting.quasis[0].value.cooked = String(val);
138
226
  return existingNode;
@@ -148,86 +236,58 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
148
236
  }, true)], []);
149
237
  return b.literal(val);
150
238
  }
151
- if (Array.isArray(val)) if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {
152
- const elements = [...unwrappedExisting.elements];
153
- val.forEach((item, i) => {
154
- elements[i] = buildNodeForValue(item, elements[i], fallbackLocale, requiredImports);
155
- });
156
- if (elements.length > val.length) elements.length = val.length;
157
- unwrappedExisting.elements = elements;
158
- return existingNode;
159
- } else return b.arrayExpression(val.map((item) => buildNodeForValue(item, null, fallbackLocale, requiredImports)));
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
+ }
160
254
  const nodeType = val && typeof val === "object" && !Array.isArray(val) ? getNodeType(val) : null;
161
- if (nodeType && [
162
- NodeTypes.TRANSLATION,
163
- NodeTypes.ENUMERATION,
164
- NodeTypes.PLURAL,
165
- NodeTypes.CONDITION,
166
- NodeTypes.GENDER,
167
- NodeTypes.SELECT,
168
- NodeTypes.INSERTION,
169
- NodeTypes.MARKDOWN,
170
- NodeTypes.HTML,
171
- NodeTypes.FILE,
172
- NodeTypes.NESTED,
173
- NodeTypes.ARRAY,
174
- NodeTypes.OBJECT,
175
- NodeTypes.REACT_NODE,
176
- NodeTypes.NUMBER,
177
- NodeTypes.BOOLEAN,
178
- NodeTypes.NULL,
179
- NodeTypes.UNKNOWN
180
- ].includes(nodeType) && nodeType !== NodeTypes.TEXT) {
255
+ if (nodeType) {
256
+ const strategy = nodeTypeStrategies[nodeType];
257
+ if (strategy.kind === "preserve") return existingNode ?? SKIP_WRITE;
258
+ const hasNodeData = Object.hasOwn(val, nodeType);
181
259
  const nodeData = val[nodeType];
182
- let calleeName = "";
183
- if (nodeType === NodeTypes.TRANSLATION) calleeName = "t";
184
- else if (nodeType === NodeTypes.ENUMERATION) calleeName = "enu";
185
- else if (nodeType === NodeTypes.PLURAL) calleeName = "plural";
186
- else if (nodeType === NodeTypes.CONDITION) calleeName = "cond";
187
- else if (nodeType === NodeTypes.GENDER) calleeName = "gender";
188
- else if (nodeType === NodeTypes.SELECT) calleeName = "select";
189
- else if (nodeType === NodeTypes.INSERTION) calleeName = "insert";
190
- else if (nodeType === NodeTypes.MARKDOWN) calleeName = "md";
191
- else if (nodeType === NodeTypes.HTML) calleeName = "html";
192
- else if (nodeType === NodeTypes.FILE) calleeName = "file";
193
- else if (nodeType === NodeTypes.NESTED) calleeName = "nest";
194
- if (calleeName) requiredImports.add(calleeName);
195
- const isMatchingCall = existingNode && n.CallExpression.check(existingNode) && n.Identifier.check(existingNode.callee) && existingNode.callee.name === calleeName;
196
- if ([
197
- "t",
198
- "enu",
199
- "plural",
200
- "cond",
201
- "gender",
202
- "select"
203
- ].includes(calleeName)) {
204
- let objArg = null;
205
- if (isMatchingCall && existingNode.arguments.length > 0 && n.ObjectExpression.check(existingNode.arguments[0])) objArg = existingNode.arguments[0];
206
- else objArg = b.objectExpression([]);
207
- updateObjectLiteral(objArg, nodeData, fallbackLocale, requiredImports);
208
- return isMatchingCall ? existingNode : b.callExpression(b.identifier(calleeName), [objArg]);
209
- }
210
- if ([
211
- "md",
212
- "html",
213
- "insert",
214
- "file"
215
- ].includes(calleeName)) {
216
- const argNode = buildNodeForValue(nodeData, isMatchingCall && existingNode.arguments.length > 0 ? existingNode.arguments[0] : null, fallbackLocale, requiredImports);
217
- if (isMatchingCall) {
218
- existingNode.arguments[0] = argNode;
219
- return existingNode;
260
+ if (strategy.kind !== "structural" && hasNodeData) {
261
+ if (strategy.kind === "unwrap") return buildNodeForValue(nodeData, existingNode, fallbackLocale, requiredImports);
262
+ const { helper } = strategy;
263
+ requiredImports.add(helper);
264
+ const isMatchingCall = existingNode && n.CallExpression.check(existingNode) && n.Identifier.check(existingNode.callee) && existingNode.callee.name === helper;
265
+ if (strategy.kind === "helperRecord") {
266
+ const recordArgument = isMatchingCall && existingNode.arguments.length > 0 && n.ObjectExpression.check(existingNode.arguments[0]) ? existingNode.arguments[0] : b.objectExpression([]);
267
+ updateObjectLiteral(recordArgument, nodeData ?? {}, fallbackLocale, requiredImports);
268
+ const callArguments = [recordArgument, ...strategy.getExtraArguments?.(val) ?? []];
269
+ if (isMatchingCall) {
270
+ syncCallArguments(existingNode, callArguments);
271
+ return existingNode;
272
+ }
273
+ return b.callExpression(b.identifier(helper), callArguments);
220
274
  }
221
- return b.callExpression(b.identifier(calleeName), [argNode]);
222
- }
223
- if (calleeName === "nest") {
224
- const args = [b.literal(nodeData.dictionaryKey)];
225
- if (nodeData.path) args.push(b.literal(nodeData.path));
275
+ if (strategy.kind === "helperValue") {
276
+ const contentArgument = buildNodeForValue(nodeData, isMatchingCall && existingNode.arguments.length > 0 ? existingNode.arguments[0] : null, fallbackLocale, requiredImports);
277
+ if (contentArgument === SKIP_WRITE) return existingNode ?? SKIP_WRITE;
278
+ if (isMatchingCall) {
279
+ syncCallArguments(existingNode, [contentArgument, ...existingNode.arguments.slice(1)]);
280
+ return existingNode;
281
+ }
282
+ return b.callExpression(b.identifier(helper), [contentArgument]);
283
+ }
284
+ const callArguments = [b.literal(nodeData?.dictionaryKey ?? "")];
285
+ if (nodeData?.path) callArguments.push(b.literal(nodeData.path));
226
286
  if (isMatchingCall) {
227
- existingNode.arguments = args;
287
+ syncCallArguments(existingNode, callArguments);
228
288
  return existingNode;
229
289
  }
230
- return b.callExpression(b.identifier("nest"), args);
290
+ return b.callExpression(b.identifier(helper), callArguments);
231
291
  }
232
292
  }
233
293
  const objNode = unwrappedExisting && n.ObjectExpression.check(unwrappedExisting) ? unwrappedExisting : b.objectExpression([]);
@@ -241,10 +301,13 @@ const updateObjectLiteral = (node, data, fallbackLocale, requiredImports) => {
241
301
  for (const [key, val] of Object.entries(data)) {
242
302
  if (val === void 0) continue;
243
303
  const existingProp = getMatchingProperty(node, key);
244
- if (existingProp) existingProp.value = buildNodeForValue(val, existingProp.value, fallbackLocale, requiredImports);
245
- else {
304
+ if (existingProp) {
305
+ const valueNode = buildNodeForValue(val, existingProp.value, fallbackLocale, requiredImports);
306
+ if (valueNode !== SKIP_WRITE) existingProp.value = valueNode;
307
+ } else {
246
308
  const keyNode = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? b.identifier(key) : b.literal(key);
247
309
  const valueNode = buildNodeForValue(val, null, fallbackLocale, requiredImports);
310
+ if (valueNode === SKIP_WRITE) continue;
248
311
  node.properties.push(b.property("init", keyNode, valueNode));
249
312
  }
250
313
  }
@@ -288,17 +351,18 @@ const addImports = (ast, requiredImports, isESM) => {
288
351
  });
289
352
  const missingCore = Array.from(requiredImports).filter((imp) => !existingCoreImports.has(imp));
290
353
  if (missingCore.length === 0) return;
291
- if (isESM) if (coreImportPath) {
292
- missingCore.forEach((imp) => {
293
- coreImportPath.node.specifiers.push(b.importSpecifier(b.identifier(imp)));
294
- });
295
- 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
+ }
296
365
  } else {
297
- const specifiers = missingCore.sort().map((imp) => b.importSpecifier(b.identifier(imp)));
298
- const newImport = b.importDeclaration(specifiers, b.literal("intlayer"));
299
- ast.program.body.unshift(newImport);
300
- }
301
- else {
302
366
  let insertIndex = 0;
303
367
  if (ast.program.body.length > 0 && n.ExpressionStatement.check(ast.program.body[0]) && n.Literal.check(ast.program.body[0].expression)) insertIndex = 1;
304
368
  const cjsLines = [];