@intlayer/engine 9.0.0-canary.16 → 9.0.0-canary.18

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 (597) hide show
  1. package/dist/cjs/_virtual/_utils_asset.cjs +4 -3
  2. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs +0 -1
  3. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  4. package/dist/cjs/buildIntlayerDictionary/processContentDeclaration.cjs +0 -1
  5. package/dist/cjs/buildIntlayerDictionary/processContentDeclaration.cjs.map +1 -1
  6. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +0 -1
  7. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
  8. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs +0 -1
  9. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
  10. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -2
  11. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
  12. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +2 -2
  13. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
  14. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs +4 -3
  15. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
  16. package/dist/cjs/cleanOutputDir.cjs +0 -1
  17. package/dist/cjs/cleanOutputDir.cjs.map +1 -1
  18. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  19. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +0 -1
  20. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
  21. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs +0 -1
  22. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
  23. package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
  24. package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
  25. package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
  26. package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
  27. package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
  28. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  29. package/dist/cjs/createType/createType.cjs +0 -1
  30. package/dist/cjs/createType/createType.cjs.map +1 -1
  31. package/dist/cjs/detectFormatCommand.cjs +0 -1
  32. package/dist/cjs/detectFormatCommand.cjs.map +1 -1
  33. package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
  34. package/dist/cjs/docReview/computeSimilarity.cjs +1 -1
  35. package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
  36. package/dist/cjs/docReview/fingerprintBlock.cjs +3 -1
  37. package/dist/cjs/docReview/fingerprintBlock.cjs.map +1 -1
  38. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
  39. package/dist/cjs/docReview/normalizeBlock.cjs +4 -2
  40. package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
  41. package/dist/cjs/docReview/pipeline.cjs +3 -2
  42. package/dist/cjs/docReview/pipeline.cjs.map +1 -1
  43. package/dist/cjs/docReview/planActions.cjs.map +1 -1
  44. package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
  45. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  46. package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
  47. package/dist/cjs/fetchDistantDictionaries.cjs +0 -1
  48. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  49. package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
  50. package/dist/cjs/formatDictionary.cjs +0 -1
  51. package/dist/cjs/formatDictionary.cjs.map +1 -1
  52. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs +0 -1
  53. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
  54. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +0 -1
  55. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
  56. package/dist/cjs/handleContentDeclarationFileChange.cjs +0 -1
  57. package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
  58. package/dist/cjs/handleContentDeclarationFileMoved.cjs +0 -1
  59. package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
  60. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +0 -1
  61. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
  62. package/dist/cjs/init/cms.cjs.map +1 -1
  63. package/dist/cjs/init/frameworkSetup/index.cjs.map +1 -1
  64. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs +0 -1
  65. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
  66. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  67. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +4 -3
  68. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
  69. package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs.map +1 -1
  70. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs +0 -1
  71. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
  72. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  73. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -2
  74. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
  75. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  76. package/dist/cjs/init/index.cjs.map +1 -1
  77. package/dist/cjs/init/utils/astImports.cjs.map +1 -1
  78. package/dist/cjs/init/utils/configManipulation.cjs +12 -6
  79. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  80. package/dist/cjs/init/utils/fileSystem.cjs +1 -1
  81. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  82. package/dist/cjs/init/utils/githubActions.cjs +0 -1
  83. package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
  84. package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
  85. package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
  86. package/dist/cjs/init/utils/packageManager.cjs +4 -3
  87. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  88. package/dist/cjs/init/utils/tsConfig.cjs +0 -1
  89. package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
  90. package/dist/cjs/init/utils/version.cjs.map +1 -1
  91. package/dist/cjs/initConfig/index.cjs +0 -1
  92. package/dist/cjs/initConfig/index.cjs.map +1 -1
  93. package/dist/cjs/installLSP.cjs.map +1 -1
  94. package/dist/cjs/installMCP/installMCP.cjs.map +1 -1
  95. package/dist/cjs/installSkills/index.cjs +1 -1
  96. package/dist/cjs/installSkills/index.cjs.map +1 -1
  97. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  98. package/dist/cjs/listGitFiles.cjs.map +1 -1
  99. package/dist/cjs/listProjects.cjs.map +1 -1
  100. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +0 -1
  101. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
  102. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +3 -3
  103. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  104. package/dist/cjs/loadDictionaries/loadDictionaries.cjs +3 -2
  105. package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
  106. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs +0 -1
  107. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
  108. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs +0 -1
  109. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
  110. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +2 -2
  111. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  112. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +0 -1
  113. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
  114. package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
  115. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs +0 -1
  116. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  117. package/dist/cjs/logConfigDetails.cjs +6 -3
  118. package/dist/cjs/logConfigDetails.cjs.map +1 -1
  119. package/dist/cjs/prepareIntlayer.cjs +2 -1
  120. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  121. package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
  122. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +0 -1
  123. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
  124. package/dist/cjs/scan/analyzeBundleContent.cjs +0 -1
  125. package/dist/cjs/scan/analyzeBundleContent.cjs.map +1 -1
  126. package/dist/cjs/scan/calculateScore.cjs.map +1 -1
  127. package/dist/cjs/scan/checks.cjs +0 -1
  128. package/dist/cjs/scan/checks.cjs.map +1 -1
  129. package/dist/cjs/scan/parseHtml.cjs.map +1 -1
  130. package/dist/cjs/scan/scanWebsite.cjs +2 -2
  131. package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
  132. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
  133. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +9 -4
  134. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
  135. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
  136. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
  137. package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
  138. package/dist/cjs/utils/buildComponentFilesList.cjs +2 -2
  139. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  140. package/dist/cjs/utils/buildFilesList.cjs +2 -1
  141. package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
  142. package/dist/cjs/utils/chunkJSON.cjs +2 -1
  143. package/dist/cjs/utils/chunkJSON.cjs.map +1 -1
  144. package/dist/cjs/utils/formatter.cjs.map +1 -1
  145. package/dist/cjs/utils/getChunk.cjs.map +1 -1
  146. package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
  147. package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
  148. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  149. package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
  150. package/dist/cjs/utils/pLimit.cjs.map +1 -1
  151. package/dist/cjs/utils/parallelize.cjs.map +1 -1
  152. package/dist/cjs/utils/parallelizeGlobal.cjs.map +1 -1
  153. package/dist/cjs/utils/readDictionariesFromDisk.cjs +0 -1
  154. package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
  155. package/dist/cjs/utils/recastBabelParser.cjs +3 -4
  156. package/dist/cjs/utils/recastBabelParser.cjs.map +1 -1
  157. package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
  158. package/dist/cjs/utils/resolveObjectPromises.cjs +8 -2
  159. package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
  160. package/dist/cjs/utils/resolveRelativePath.cjs +0 -1
  161. package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
  162. package/dist/cjs/utils/runOnce.cjs.map +1 -1
  163. package/dist/cjs/utils/runParallel/bin.cjs +0 -1
  164. package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
  165. package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
  166. package/dist/cjs/utils/runParallel/index.cjs +2 -3
  167. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  168. package/dist/cjs/utils/runParallel/pidTree.cjs.map +1 -1
  169. package/dist/cjs/utils/runParallel/ps.cjs.map +1 -1
  170. package/dist/cjs/utils/runParallel/runTask.cjs +0 -1
  171. package/dist/cjs/utils/runParallel/runTask.cjs.map +1 -1
  172. package/dist/cjs/utils/runParallel/spawnPosix.cjs +0 -1
  173. package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
  174. package/dist/cjs/utils/runParallel/spawnWin32.cjs +0 -1
  175. package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
  176. package/dist/cjs/utils/runParallel/wmic.cjs.map +1 -1
  177. package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
  178. package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
  179. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
  180. package/dist/cjs/watcher.cjs.map +1 -1
  181. package/dist/cjs/writeConfiguration/generateConfigurationContent.cjs.map +1 -1
  182. package/dist/cjs/writeConfiguration/index.cjs +0 -1
  183. package/dist/cjs/writeConfiguration/index.cjs.map +1 -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.map +1 -1
  187. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
  188. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +3 -4
  189. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  190. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +0 -1
  191. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
  192. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +5 -4
  193. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  194. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +1 -2
  195. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  196. package/dist/cjs/writeFileIfChanged.cjs +0 -1
  197. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  198. package/dist/cjs/writeJsonIfChanged.cjs.map +1 -1
  199. package/dist/esm/_virtual/_utils_asset.mjs +4 -2
  200. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs.map +1 -1
  201. package/dist/esm/buildIntlayerDictionary/processContentDeclaration.mjs.map +1 -1
  202. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
  203. package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs.map +1 -1
  204. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
  205. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
  206. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +2 -1
  207. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
  208. package/dist/esm/buildIntlayerDictionary/writeUnmergedDictionary.mjs +4 -2
  209. package/dist/esm/buildIntlayerDictionary/writeUnmergedDictionary.mjs.map +1 -1
  210. package/dist/esm/cleanOutputDir.mjs.map +1 -1
  211. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  212. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
  213. package/dist/esm/createDictionaryEntryPoint/generateDictionaryListContent.mjs.map +1 -1
  214. package/dist/esm/createDictionaryEntryPoint/getBuiltDictionariesPath.mjs.map +1 -1
  215. package/dist/esm/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.mjs.map +1 -1
  216. package/dist/esm/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.mjs.map +1 -1
  217. package/dist/esm/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.mjs.map +1 -1
  218. package/dist/esm/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.mjs.map +1 -1
  219. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  220. package/dist/esm/createType/createType.mjs.map +1 -1
  221. package/dist/esm/detectFormatCommand.mjs.map +1 -1
  222. package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
  223. package/dist/esm/docReview/computeSimilarity.mjs +1 -1
  224. package/dist/esm/docReview/computeSimilarity.mjs.map +1 -1
  225. package/dist/esm/docReview/fingerprintBlock.mjs +3 -1
  226. package/dist/esm/docReview/fingerprintBlock.mjs.map +1 -1
  227. package/dist/esm/docReview/mapChangedLinesToBlocks.mjs.map +1 -1
  228. package/dist/esm/docReview/normalizeBlock.mjs +4 -2
  229. package/dist/esm/docReview/normalizeBlock.mjs.map +1 -1
  230. package/dist/esm/docReview/pipeline.mjs +3 -2
  231. package/dist/esm/docReview/pipeline.mjs.map +1 -1
  232. package/dist/esm/docReview/planActions.mjs.map +1 -1
  233. package/dist/esm/docReview/rebuildDocument.mjs.map +1 -1
  234. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  235. package/dist/esm/docReview/segmentDocument.mjs.map +1 -1
  236. package/dist/esm/fetchDistantDictionaries.mjs.map +1 -1
  237. package/dist/esm/filterInvalidDictionaries.mjs.map +1 -1
  238. package/dist/esm/formatDictionary.mjs.map +1 -1
  239. package/dist/esm/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.mjs.map +1 -1
  240. package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
  241. package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
  242. package/dist/esm/handleContentDeclarationFileMoved.mjs.map +1 -1
  243. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
  244. package/dist/esm/init/cms.mjs.map +1 -1
  245. package/dist/esm/init/frameworkSetup/index.mjs.map +1 -1
  246. package/dist/esm/init/frameworkSetup/nextAppRouter/detect.mjs.map +1 -1
  247. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  248. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +4 -3
  249. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
  250. package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs.map +1 -1
  251. package/dist/esm/init/frameworkSetup/tanstackStart/detect.mjs.map +1 -1
  252. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  253. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -2
  254. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
  255. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  256. package/dist/esm/init/index.mjs.map +1 -1
  257. package/dist/esm/init/utils/astImports.mjs.map +1 -1
  258. package/dist/esm/init/utils/configManipulation.mjs +12 -6
  259. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  260. package/dist/esm/init/utils/fileSystem.mjs +1 -1
  261. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  262. package/dist/esm/init/utils/githubActions.mjs.map +1 -1
  263. package/dist/esm/init/utils/jsonParser.mjs.map +1 -1
  264. package/dist/esm/init/utils/nextCompilerBabel.mjs.map +1 -1
  265. package/dist/esm/init/utils/packageManager.mjs +4 -2
  266. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  267. package/dist/esm/init/utils/tsConfig.mjs.map +1 -1
  268. package/dist/esm/init/utils/version.mjs.map +1 -1
  269. package/dist/esm/initConfig/index.mjs.map +1 -1
  270. package/dist/esm/installLSP.mjs.map +1 -1
  271. package/dist/esm/installMCP/installMCP.mjs.map +1 -1
  272. package/dist/esm/installSkills/index.mjs +1 -1
  273. package/dist/esm/installSkills/index.mjs.map +1 -1
  274. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  275. package/dist/esm/listGitFiles.mjs.map +1 -1
  276. package/dist/esm/listProjects.mjs.map +1 -1
  277. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
  278. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +3 -2
  279. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  280. package/dist/esm/loadDictionaries/loadDictionaries.mjs +3 -2
  281. package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
  282. package/dist/esm/loadDictionaries/loadLocalDictionaries.mjs.map +1 -1
  283. package/dist/esm/loadDictionaries/loadMarkdownContentDeclaration.mjs.map +1 -1
  284. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +2 -1
  285. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
  286. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
  287. package/dist/esm/loadDictionaries/log.mjs.map +1 -1
  288. package/dist/esm/loadDictionaries/logTypeScriptErrors.mjs.map +1 -1
  289. package/dist/esm/logConfigDetails.mjs +6 -3
  290. package/dist/esm/logConfigDetails.mjs.map +1 -1
  291. package/dist/esm/prepareIntlayer.mjs +2 -1
  292. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  293. package/dist/esm/reduceDictionaryContent/applyMask.mjs.map +1 -1
  294. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
  295. package/dist/esm/scan/analyzeBundleContent.mjs.map +1 -1
  296. package/dist/esm/scan/calculateScore.mjs.map +1 -1
  297. package/dist/esm/scan/checks.mjs.map +1 -1
  298. package/dist/esm/scan/parseHtml.mjs.map +1 -1
  299. package/dist/esm/scan/scanWebsite.mjs +2 -1
  300. package/dist/esm/scan/scanWebsite.mjs.map +1 -1
  301. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
  302. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +9 -3
  303. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
  304. package/dist/esm/syncPluginKit/extractKeyAndLocaleFromPath.mjs.map +1 -1
  305. package/dist/esm/syncPluginKit/filePathPatternHelpers.mjs.map +1 -1
  306. package/dist/esm/utils/autoDecorateContent.mjs.map +1 -1
  307. package/dist/esm/utils/buildComponentFilesList.mjs +2 -2
  308. package/dist/esm/utils/buildComponentFilesList.mjs.map +1 -1
  309. package/dist/esm/utils/buildFilesList.mjs +2 -1
  310. package/dist/esm/utils/buildFilesList.mjs.map +1 -1
  311. package/dist/esm/utils/chunkJSON.mjs +2 -1
  312. package/dist/esm/utils/chunkJSON.mjs.map +1 -1
  313. package/dist/esm/utils/formatter.mjs.map +1 -1
  314. package/dist/esm/utils/getChunk.mjs.map +1 -1
  315. package/dist/esm/utils/getContentExtension.mjs.map +1 -1
  316. package/dist/esm/utils/getFormatFromExtension.mjs.map +1 -1
  317. package/dist/esm/utils/getPathHash.mjs.map +1 -1
  318. package/dist/esm/utils/mergeChunks.mjs.map +1 -1
  319. package/dist/esm/utils/pLimit.mjs.map +1 -1
  320. package/dist/esm/utils/parallelize.mjs.map +1 -1
  321. package/dist/esm/utils/parallelizeGlobal.mjs.map +1 -1
  322. package/dist/esm/utils/readDictionariesFromDisk.mjs.map +1 -1
  323. package/dist/esm/utils/recastBabelParser.mjs +1 -1
  324. package/dist/esm/utils/recastBabelParser.mjs.map +1 -1
  325. package/dist/esm/utils/reduceObjectFormat.mjs.map +1 -1
  326. package/dist/esm/utils/resolveObjectPromises.mjs +8 -2
  327. package/dist/esm/utils/resolveObjectPromises.mjs.map +1 -1
  328. package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
  329. package/dist/esm/utils/runOnce.mjs.map +1 -1
  330. package/dist/esm/utils/runParallel/bin.mjs.map +1 -1
  331. package/dist/esm/utils/runParallel/bootstrap.mjs.map +1 -1
  332. package/dist/esm/utils/runParallel/index.mjs +2 -2
  333. package/dist/esm/utils/runParallel/index.mjs.map +1 -1
  334. package/dist/esm/utils/runParallel/pidTree.mjs.map +1 -1
  335. package/dist/esm/utils/runParallel/ps.mjs.map +1 -1
  336. package/dist/esm/utils/runParallel/runTask.mjs.map +1 -1
  337. package/dist/esm/utils/runParallel/spawnPosix.mjs.map +1 -1
  338. package/dist/esm/utils/runParallel/spawnWin32.mjs.map +1 -1
  339. package/dist/esm/utils/runParallel/wmic.mjs.map +1 -1
  340. package/dist/esm/utils/sortAlphabetically.mjs.map +1 -1
  341. package/dist/esm/utils/splitTextByLine.mjs.map +1 -1
  342. package/dist/esm/utils/verifyIdenticObjectFormat.mjs.map +1 -1
  343. package/dist/esm/watcher.mjs.map +1 -1
  344. package/dist/esm/writeConfiguration/generateConfigurationContent.mjs.map +1 -1
  345. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  346. package/dist/esm/writeContentDeclaration/detectExportedComponentName.mjs.map +1 -1
  347. package/dist/esm/writeContentDeclaration/processContentDeclarationContent.mjs.map +1 -1
  348. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  349. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
  350. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +3 -3
  351. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  352. package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
  353. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +5 -3
  354. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  355. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +1 -1
  356. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  357. package/dist/esm/writeFileIfChanged.mjs.map +1 -1
  358. package/dist/esm/writeJsonIfChanged.mjs.map +1 -1
  359. package/dist/types/build.d.ts +5 -0
  360. package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts +0 -1
  361. package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts.map +1 -1
  362. package/dist/types/buildIntlayerDictionary/processContentDeclaration.d.ts +0 -1
  363. package/dist/types/buildIntlayerDictionary/processContentDeclaration.d.ts.map +1 -1
  364. package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts +4 -5
  365. package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts.map +1 -1
  366. package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts +2 -3
  367. package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts.map +1 -1
  368. package/dist/types/buildIntlayerDictionary/writeMergedDictionary.d.ts +0 -1
  369. package/dist/types/buildIntlayerDictionary/writeMergedDictionary.d.ts.map +1 -1
  370. package/dist/types/buildIntlayerDictionary/writeRemoteDictionary.d.ts +0 -1
  371. package/dist/types/buildIntlayerDictionary/writeRemoteDictionary.d.ts.map +1 -1
  372. package/dist/types/buildIntlayerDictionary/writeUnmergedDictionary.d.ts +1 -2
  373. package/dist/types/buildIntlayerDictionary/writeUnmergedDictionary.d.ts.map +1 -1
  374. package/dist/types/cleanOutputDir.d.ts +0 -1
  375. package/dist/types/cleanOutputDir.d.ts.map +1 -1
  376. package/dist/types/cleanRemovedContentDeclaration.d.ts +0 -1
  377. package/dist/types/cleanRemovedContentDeclaration.d.ts.map +1 -1
  378. package/dist/types/cli.d.ts +2 -0
  379. package/dist/types/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts +1 -3
  380. package/dist/types/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts.map +1 -1
  381. package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts +1 -3
  382. package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts.map +1 -1
  383. package/dist/types/createDictionaryEntryPoint/getBuiltDictionariesPath.d.ts +0 -1
  384. package/dist/types/createDictionaryEntryPoint/getBuiltDictionariesPath.d.ts.map +1 -1
  385. package/dist/types/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.d.ts +1 -2
  386. package/dist/types/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.d.ts.map +1 -1
  387. package/dist/types/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.d.ts +1 -2
  388. package/dist/types/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.d.ts.map +1 -1
  389. package/dist/types/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.d.ts +0 -1
  390. package/dist/types/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.d.ts.map +1 -1
  391. package/dist/types/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.d.ts +0 -1
  392. package/dist/types/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.d.ts.map +1 -1
  393. package/dist/types/createType/createModuleAugmentation.d.ts +0 -1
  394. package/dist/types/createType/createModuleAugmentation.d.ts.map +1 -1
  395. package/dist/types/createType/createType.d.ts +0 -1
  396. package/dist/types/createType/createType.d.ts.map +1 -1
  397. package/dist/types/detectFormatCommand.d.ts +0 -1
  398. package/dist/types/detectFormatCommand.d.ts.map +1 -1
  399. package/dist/types/docReview/alignBlocks.d.ts +0 -1
  400. package/dist/types/docReview/alignBlocks.d.ts.map +1 -1
  401. package/dist/types/docReview/computeSimilarity.d.ts.map +1 -1
  402. package/dist/types/docReview/fingerprintBlock.d.ts +0 -1
  403. package/dist/types/docReview/fingerprintBlock.d.ts.map +1 -1
  404. package/dist/types/docReview/mapChangedLinesToBlocks.d.ts +0 -1
  405. package/dist/types/docReview/mapChangedLinesToBlocks.d.ts.map +1 -1
  406. package/dist/types/docReview/normalizeBlock.d.ts +0 -1
  407. package/dist/types/docReview/normalizeBlock.d.ts.map +1 -1
  408. package/dist/types/docReview/pipeline.d.ts +6 -8
  409. package/dist/types/docReview/pipeline.d.ts.map +1 -1
  410. package/dist/types/docReview/planActions.d.ts +0 -1
  411. package/dist/types/docReview/planActions.d.ts.map +1 -1
  412. package/dist/types/docReview/rebuildDocument.d.ts +6 -8
  413. package/dist/types/docReview/rebuildDocument.d.ts.map +1 -1
  414. package/dist/types/docReview/reviewReport.d.ts +23 -14
  415. package/dist/types/docReview/reviewReport.d.ts.map +1 -1
  416. package/dist/types/docReview/segmentDocument.d.ts +0 -1
  417. package/dist/types/docReview/segmentDocument.d.ts.map +1 -1
  418. package/dist/types/docReview/types.d.ts +10 -4
  419. package/dist/types/docReview/types.d.ts.map +1 -1
  420. package/dist/types/fetchDistantDictionaries.d.ts +1 -1
  421. package/dist/types/fetchDistantDictionaries.d.ts.map +1 -1
  422. package/dist/types/filterInvalidDictionaries.d.ts +0 -1
  423. package/dist/types/filterInvalidDictionaries.d.ts.map +1 -1
  424. package/dist/types/formatDictionary.d.ts +27 -30
  425. package/dist/types/formatDictionary.d.ts.map +1 -1
  426. package/dist/types/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.d.ts +0 -1
  427. package/dist/types/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.d.ts.map +1 -1
  428. package/dist/types/handleAdditionalContentDeclarationFile.d.ts +0 -1
  429. package/dist/types/handleAdditionalContentDeclarationFile.d.ts.map +1 -1
  430. package/dist/types/handleContentDeclarationFileChange.d.ts +0 -1
  431. package/dist/types/handleContentDeclarationFileChange.d.ts.map +1 -1
  432. package/dist/types/handleContentDeclarationFileMoved.d.ts +0 -1
  433. package/dist/types/handleContentDeclarationFileMoved.d.ts.map +1 -1
  434. package/dist/types/handleUnlinkedContentDeclarationFile.d.ts +0 -1
  435. package/dist/types/handleUnlinkedContentDeclarationFile.d.ts.map +1 -1
  436. package/dist/types/init/cms.d.ts +2 -6
  437. package/dist/types/init/cms.d.ts.map +1 -1
  438. package/dist/types/init/frameworkSetup/index.d.ts +0 -1
  439. package/dist/types/init/frameworkSetup/index.d.ts.map +1 -1
  440. package/dist/types/init/frameworkSetup/nextAppRouter/detect.d.ts +3 -2
  441. package/dist/types/init/frameworkSetup/nextAppRouter/detect.d.ts.map +1 -1
  442. package/dist/types/init/frameworkSetup/nextAppRouter/index.d.ts +0 -1
  443. package/dist/types/init/frameworkSetup/nextAppRouter/index.d.ts.map +1 -1
  444. package/dist/types/init/frameworkSetup/nextAppRouter/restructure.d.ts.map +1 -1
  445. package/dist/types/init/frameworkSetup/nextAppRouter/templates.d.ts.map +1 -1
  446. package/dist/types/init/frameworkSetup/nextAppRouter/transforms.d.ts.map +1 -1
  447. package/dist/types/init/frameworkSetup/tanstackStart/detect.d.ts +3 -1
  448. package/dist/types/init/frameworkSetup/tanstackStart/detect.d.ts.map +1 -1
  449. package/dist/types/init/frameworkSetup/tanstackStart/index.d.ts +0 -1
  450. package/dist/types/init/frameworkSetup/tanstackStart/index.d.ts.map +1 -1
  451. package/dist/types/init/frameworkSetup/tanstackStart/restructure.d.ts +0 -1
  452. package/dist/types/init/frameworkSetup/tanstackStart/restructure.d.ts.map +1 -1
  453. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  454. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  455. package/dist/types/init/frameworkSetup/types.d.ts +9 -5
  456. package/dist/types/init/frameworkSetup/types.d.ts.map +1 -1
  457. package/dist/types/init/index.d.ts +7 -3
  458. package/dist/types/init/index.d.ts.map +1 -1
  459. package/dist/types/init/utils/astImports.d.ts.map +1 -1
  460. package/dist/types/init/utils/configManipulation.d.ts +0 -1
  461. package/dist/types/init/utils/configManipulation.d.ts.map +1 -1
  462. package/dist/types/init/utils/fileSystem.d.ts +6 -3
  463. package/dist/types/init/utils/fileSystem.d.ts.map +1 -1
  464. package/dist/types/init/utils/githubActions.d.ts +7 -4
  465. package/dist/types/init/utils/githubActions.d.ts.map +1 -1
  466. package/dist/types/init/utils/jsonParser.d.ts.map +1 -1
  467. package/dist/types/init/utils/nextCompilerBabel.d.ts +2 -8
  468. package/dist/types/init/utils/nextCompilerBabel.d.ts.map +1 -1
  469. package/dist/types/init/utils/packageManager.d.ts +9 -3
  470. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  471. package/dist/types/init/utils/tsConfig.d.ts.map +1 -1
  472. package/dist/types/init/utils/version.d.ts.map +1 -1
  473. package/dist/types/initConfig/index.d.ts +2 -2
  474. package/dist/types/initConfig/index.d.ts.map +1 -1
  475. package/dist/types/installLSP.d.ts.map +1 -1
  476. package/dist/types/installMCP/installMCP.d.ts +0 -1
  477. package/dist/types/installMCP/installMCP.d.ts.map +1 -1
  478. package/dist/types/installSkills/index.d.ts +14 -14
  479. package/dist/types/installSkills/index.d.ts.map +1 -1
  480. package/dist/types/listDictionariesPath.d.ts +1 -3
  481. package/dist/types/listDictionariesPath.d.ts.map +1 -1
  482. package/dist/types/listGitFiles.d.ts +2 -11
  483. package/dist/types/listGitFiles.d.ts.map +1 -1
  484. package/dist/types/listProjects.d.ts.map +1 -1
  485. package/dist/types/loadDictionaries/getIntlayerBundle.d.ts +0 -1
  486. package/dist/types/loadDictionaries/getIntlayerBundle.d.ts.map +1 -1
  487. package/dist/types/loadDictionaries/loadContentDeclaration.d.ts +0 -1
  488. package/dist/types/loadDictionaries/loadContentDeclaration.d.ts.map +1 -1
  489. package/dist/types/loadDictionaries/loadDictionaries.d.ts +0 -1
  490. package/dist/types/loadDictionaries/loadDictionaries.d.ts.map +1 -1
  491. package/dist/types/loadDictionaries/loadLocalDictionaries.d.ts +0 -1
  492. package/dist/types/loadDictionaries/loadLocalDictionaries.d.ts.map +1 -1
  493. package/dist/types/loadDictionaries/loadMarkdownContentDeclaration.d.ts +0 -1
  494. package/dist/types/loadDictionaries/loadMarkdownContentDeclaration.d.ts.map +1 -1
  495. package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts +1 -3
  496. package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts.map +1 -1
  497. package/dist/types/loadDictionaries/loadYamlContentDeclaration.d.ts +0 -1
  498. package/dist/types/loadDictionaries/loadYamlContentDeclaration.d.ts.map +1 -1
  499. package/dist/types/loadDictionaries/log.d.ts +0 -1
  500. package/dist/types/loadDictionaries/log.d.ts.map +1 -1
  501. package/dist/types/loadDictionaries/logTypeScriptErrors.d.ts +0 -1
  502. package/dist/types/loadDictionaries/logTypeScriptErrors.d.ts.map +1 -1
  503. package/dist/types/logConfigDetails.d.ts +0 -1
  504. package/dist/types/logConfigDetails.d.ts.map +1 -1
  505. package/dist/types/prepareIntlayer.d.ts +0 -1
  506. package/dist/types/prepareIntlayer.d.ts.map +1 -1
  507. package/dist/types/reduceDictionaryContent/applyMask.d.ts +0 -1
  508. package/dist/types/reduceDictionaryContent/applyMask.d.ts.map +1 -1
  509. package/dist/types/reduceDictionaryContent/reduceDictionaryContent.d.ts +0 -1
  510. package/dist/types/reduceDictionaryContent/reduceDictionaryContent.d.ts.map +1 -1
  511. package/dist/types/scan/analyzeBundleContent.d.ts +0 -1
  512. package/dist/types/scan/analyzeBundleContent.d.ts.map +1 -1
  513. package/dist/types/scan/calculateScore.d.ts +3 -1
  514. package/dist/types/scan/calculateScore.d.ts.map +1 -1
  515. package/dist/types/scan/checks.d.ts +0 -1
  516. package/dist/types/scan/checks.d.ts.map +1 -1
  517. package/dist/types/scan/parseHtml.d.ts.map +1 -1
  518. package/dist/types/scan/scanWebsite.d.ts +0 -1
  519. package/dist/types/scan/scanWebsite.d.ts.map +1 -1
  520. package/dist/types/scan/types.d.ts +32 -17
  521. package/dist/types/scan/types.d.ts.map +1 -1
  522. package/dist/types/syncPluginKit/createFileAdapter.d.ts +0 -1
  523. package/dist/types/syncPluginKit/createFileAdapter.d.ts.map +1 -1
  524. package/dist/types/syncPluginKit/createSyncPlugin.d.ts +0 -1
  525. package/dist/types/syncPluginKit/createSyncPlugin.d.ts.map +1 -1
  526. package/dist/types/syncPluginKit/extractKeyAndLocaleFromPath.d.ts +0 -1
  527. package/dist/types/syncPluginKit/extractKeyAndLocaleFromPath.d.ts.map +1 -1
  528. package/dist/types/syncPluginKit/filePathPatternHelpers.d.ts +0 -1
  529. package/dist/types/syncPluginKit/filePathPatternHelpers.d.ts.map +1 -1
  530. package/dist/types/syncPluginKit/types.d.ts +8 -4
  531. package/dist/types/syncPluginKit/types.d.ts.map +1 -1
  532. package/dist/types/utils/autoDecorateContent.d.ts.map +1 -1
  533. package/dist/types/utils/buildComponentFilesList.d.ts +0 -1
  534. package/dist/types/utils/buildComponentFilesList.d.ts.map +1 -1
  535. package/dist/types/utils/buildFilesList.d.ts +0 -1
  536. package/dist/types/utils/buildFilesList.d.ts.map +1 -1
  537. package/dist/types/utils/chunkJSON.d.ts.map +1 -1
  538. package/dist/types/utils/formatter.d.ts +0 -1
  539. package/dist/types/utils/formatter.d.ts.map +1 -1
  540. package/dist/types/utils/getChunk.d.ts.map +1 -1
  541. package/dist/types/utils/getContentExtension.d.ts +1 -2
  542. package/dist/types/utils/getContentExtension.d.ts.map +1 -1
  543. package/dist/types/utils/getFormatFromExtension.d.ts.map +1 -1
  544. package/dist/types/utils/getPathHash.d.ts.map +1 -1
  545. package/dist/types/utils/mergeChunks.d.ts.map +1 -1
  546. package/dist/types/utils/pLimit.d.ts.map +1 -1
  547. package/dist/types/utils/parallelize.d.ts.map +1 -1
  548. package/dist/types/utils/parallelizeGlobal.d.ts +3 -2
  549. package/dist/types/utils/parallelizeGlobal.d.ts.map +1 -1
  550. package/dist/types/utils/readDictionariesFromDisk.d.ts.map +1 -1
  551. package/dist/types/utils/recastBabelParser.d.ts.map +1 -1
  552. package/dist/types/utils/reduceObjectFormat.d.ts.map +1 -1
  553. package/dist/types/utils/resolveObjectPromises.d.ts.map +1 -1
  554. package/dist/types/utils/resolveRelativePath.d.ts.map +1 -1
  555. package/dist/types/utils/runOnce.d.ts.map +1 -1
  556. package/dist/types/utils/runParallel/bin.d.ts +0 -1
  557. package/dist/types/utils/runParallel/bin.d.ts.map +1 -1
  558. package/dist/types/utils/runParallel/bootstrap.d.ts.map +1 -1
  559. package/dist/types/utils/runParallel/index.d.ts.map +1 -1
  560. package/dist/types/utils/runParallel/pidTree.d.ts.map +1 -1
  561. package/dist/types/utils/runParallel/ps.d.ts.map +1 -1
  562. package/dist/types/utils/runParallel/runTask.d.ts.map +1 -1
  563. package/dist/types/utils/runParallel/spawnPosix.d.ts +0 -1
  564. package/dist/types/utils/runParallel/spawnPosix.d.ts.map +1 -1
  565. package/dist/types/utils/runParallel/spawnWin32.d.ts +0 -1
  566. package/dist/types/utils/runParallel/spawnWin32.d.ts.map +1 -1
  567. package/dist/types/utils/runParallel/wmic.d.ts.map +1 -1
  568. package/dist/types/utils/sortAlphabetically.d.ts.map +1 -1
  569. package/dist/types/utils/splitTextByLine.d.ts.map +1 -1
  570. package/dist/types/utils/verifyIdenticObjectFormat.d.ts.map +1 -1
  571. package/dist/types/watcher.d.ts +0 -1
  572. package/dist/types/watcher.d.ts.map +1 -1
  573. package/dist/types/writeConfiguration/generateConfigurationContent.d.ts +1 -2
  574. package/dist/types/writeConfiguration/generateConfigurationContent.d.ts.map +1 -1
  575. package/dist/types/writeConfiguration/index.d.ts +0 -1
  576. package/dist/types/writeConfiguration/index.d.ts.map +1 -1
  577. package/dist/types/writeContentDeclaration/detectExportedComponentName.d.ts.map +1 -1
  578. package/dist/types/writeContentDeclaration/dictionaryStatus.d.ts.map +1 -1
  579. package/dist/types/writeContentDeclaration/processContentDeclarationContent.d.ts +0 -1
  580. package/dist/types/writeContentDeclaration/processContentDeclarationContent.d.ts.map +1 -1
  581. package/dist/types/writeContentDeclaration/transformJSFile.d.ts +0 -1
  582. package/dist/types/writeContentDeclaration/transformJSFile.d.ts.map +1 -1
  583. package/dist/types/writeContentDeclaration/transformJSONFile.d.ts +0 -1
  584. package/dist/types/writeContentDeclaration/transformJSONFile.d.ts.map +1 -1
  585. package/dist/types/writeContentDeclaration/writeContentDeclaration.d.ts +0 -1
  586. package/dist/types/writeContentDeclaration/writeContentDeclaration.d.ts.map +1 -1
  587. package/dist/types/writeContentDeclaration/writeJSFile.d.ts +0 -1
  588. package/dist/types/writeContentDeclaration/writeJSFile.d.ts.map +1 -1
  589. package/dist/types/writeContentDeclaration/writeMarkdownFile.d.ts +0 -1
  590. package/dist/types/writeContentDeclaration/writeMarkdownFile.d.ts.map +1 -1
  591. package/dist/types/writeContentDeclaration/writeYamlFile.d.ts +0 -1
  592. package/dist/types/writeContentDeclaration/writeYamlFile.d.ts.map +1 -1
  593. package/dist/types/writeFileIfChanged.d.ts +4 -6
  594. package/dist/types/writeFileIfChanged.d.ts.map +1 -1
  595. package/dist/types/writeJsonIfChanged.d.ts +1 -3
  596. package/dist/types/writeJsonIfChanged.d.ts.map +1 -1
  597. package/package.json +20 -13
@@ -1 +1 @@
1
- {"version":3,"file":"checks.cjs","names":["extractHtmlLang","extractHtmlDir","hasCanonical","extractHreflangs","ALL_LOCALES","analyzeBundleContent"],"sources":["../../../src/scan/checks.ts"],"sourcesContent":["import { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport { analyzeBundleContent } from './analyzeBundleContent';\nimport {\n type Anchor,\n extractHreflangs,\n extractHtmlDir,\n extractHtmlLang,\n hasCanonical,\n} from './parseHtml';\nimport type {\n BundleChunkInput,\n BundleContentAnalysis,\n ScanEvent,\n} from './types';\n\n/** Format a byte count as a human-readable size. */\nexport const formatSize = (bytes: number): string => {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(2)} KB`;\n return `${bytes} B`;\n};\n\n/**\n * Check the `<html>` element attributes (`lang`, `dir`) and the resulting\n * current-locale signal. Returns the detected language tag.\n */\nexport const checkHtmlAttributes = (\n html: string,\n targetUrl: string,\n events: ScanEvent[]\n): { langTag: string | undefined } => {\n const langTag = extractHtmlLang(html);\n const dirTag = extractHtmlDir(html);\n\n events.push({\n type: `url_htmlLang\\\\${targetUrl}`,\n status: langTag ? 'success' : 'error',\n details: {\n success: langTag,\n error: langTag ? undefined : 'Missing html lang attribute',\n },\n });\n\n events.push({\n type: `url_currentLocale\\\\${targetUrl}`,\n status: langTag ? 'success' : 'warning',\n details: {\n success: langTag,\n warning: langTag ? undefined : 'No locale detected',\n },\n });\n\n events.push({\n type: `url_htmlDir\\\\${targetUrl}`,\n status: dirTag ? 'success' : 'warning',\n details: {\n success: dirTag,\n warning: dirTag ? undefined : 'Missing html dir attribute',\n },\n });\n\n return { langTag };\n};\n\n/** Check the presence of a canonical link. */\nexport const checkCanonical = (\n html: string,\n targetUrl: string,\n events: ScanEvent[]\n): void => {\n const present = hasCanonical(html);\n events.push({\n type: `url_hasCanonical\\\\${targetUrl}`,\n status: present ? 'success' : 'warning',\n details: { warning: present ? undefined : 'Missing canonical link' },\n });\n};\n\n/**\n * Check the page's hreflang structure and collect discovered locales into\n * `localesSet`.\n */\nexport const checkLinguisticStructure = (\n html: string,\n targetUrl: string,\n localesSet: Set<string>,\n events: ScanEvent[]\n): void => {\n const langTag = extractHtmlLang(html);\n if (langTag) localesSet.add(langTag);\n\n const hreflangs = extractHreflangs(html);\n for (const { hreflang } of hreflangs) {\n if (hreflang !== 'x-default') localesSet.add(hreflang);\n }\n\n const hasXDefault = hreflangs.some((h) => h.hreflang === 'x-default');\n\n events.push({\n type: `url_hreflang\\\\${targetUrl}`,\n status: hreflangs.length > 0 ? 'success' : 'warning',\n details: {\n success: hreflangs.length > 0 ? hreflangs : undefined,\n warning: hreflangs.length === 0 ? 'No hreflang tags found' : undefined,\n },\n });\n\n events.push({\n type: `url_hasXDefault\\\\${targetUrl}`,\n status: hasXDefault ? 'success' : 'error',\n details: {\n error: hasXDefault ? undefined : 'Missing x-default hreflang link',\n },\n });\n};\n\nconst normalizeHost = (host: string): string =>\n host.startsWith('www.') ? host.slice(4) : host;\n\nconst localeValues = Object.values(ALL_LOCALES) as string[];\n\n/**\n * Check whether internal links carry a locale segment, mirroring the hosted\n * audit's URL-structure analysis but operating on parsed anchors instead of a\n * live DOM.\n */\nexport const checkUrlStructure = (\n anchors: Anchor[],\n origin: string,\n targetUrl: string,\n events: ScanEvent[]\n): void => {\n const targetHostname = normalizeHost(new URL(origin).hostname);\n\n let localizedCount = 0;\n let totalInternalCount = 0;\n const nonLocalizedLinks: string[] = [];\n\n for (const { href } of anchors) {\n if (!href || href.startsWith('#') || href.startsWith('javascript:'))\n continue;\n\n try {\n const url = new URL(href, origin);\n if (normalizeHost(url.hostname) !== targetHostname) continue;\n\n totalInternalCount++;\n const path = url.pathname.toLowerCase();\n const hostname = url.hostname.toLowerCase();\n\n const hasLocaleInPath = localeValues.some((locale) => {\n const l = locale.toLowerCase();\n return path === `/${l}` || path.includes(`/${l}/`);\n });\n const hasLocaleInSubdomain = localeValues.some((locale) => {\n const l = locale.toLowerCase();\n return hostname.startsWith(`${l}.`) || hostname.includes(`.${l}.`);\n });\n\n if (hasLocaleInPath || hasLocaleInSubdomain) {\n localizedCount++;\n } else {\n nonLocalizedLinks.push(href);\n }\n } catch {\n /* ignore malformed URLs */\n }\n }\n\n const hasLocalizedLinks = localizedCount > 0;\n const allAnchorsLocalized =\n totalInternalCount === 0 || localizedCount === totalInternalCount;\n\n events.push({\n type: `url_hasLocalizedLinks\\\\${targetUrl}`,\n status: hasLocalizedLinks ? 'success' : 'warning',\n details: {\n success: hasLocalizedLinks\n ? `${localizedCount} localized links found out of ${totalInternalCount} internal links`\n : undefined,\n warning: hasLocalizedLinks ? undefined : 'No localized links found',\n },\n });\n\n events.push({\n type: `url_allAnchorsLocalized\\\\${targetUrl}`,\n status: allAnchorsLocalized ? 'success' : 'warning',\n details: {\n warning: allAnchorsLocalized\n ? undefined\n : {\n message: 'Some internal links are not localized',\n links: nonLocalizedLinks,\n },\n },\n });\n};\n\n/**\n * Analyze the JavaScript bundles for unused locale content and emit the\n * corresponding event. Returns the analysis so callers can report on it.\n */\nexport const checkBundleContent = (\n chunks: BundleChunkInput[],\n html: string,\n currentLocale: string | undefined,\n targetUrl: string,\n totalPageSize: number,\n events: ScanEvent[]\n): BundleContentAnalysis | undefined => {\n if (!currentLocale) {\n events.push({\n type: `url_unusedBundleContent\\\\${targetUrl}`,\n status: 'warning',\n details: {\n warning: 'Cannot analyse bundle content: page locale not detected',\n },\n });\n return undefined;\n }\n\n const analysis = analyzeBundleContent(\n chunks,\n html,\n currentLocale,\n totalPageSize\n );\n\n // Status is driven by the main bundle — lazy chunks with unused content are expected.\n const mainBundleMaxUnused = analysis.mainBundleChunks.reduce(\n (max, c) => Math.max(max, c.unusedPercent),\n 0\n );\n\n const status =\n mainBundleMaxUnused === 0\n ? 'success'\n : mainBundleMaxUnused <= 30\n ? 'warning'\n : 'error';\n\n events.push({\n type: `url_unusedBundleContent\\\\${targetUrl}`,\n status,\n details: { [status]: analysis },\n });\n\n return analysis;\n};\n\n/** Fetch and check `robots.txt`, emitting robots-related events. */\nexport const checkRobots = async (\n origin: string,\n discoveredLocales: Set<string>,\n userAgent: string,\n events: ScanEvent[]\n): Promise<void> => {\n let robotsPresent = false;\n let noLocalizedUrlsForgotten = true;\n const errors: string[] = [];\n\n try {\n const response = await fetch(`${origin}/robots.txt`, {\n headers: { 'User-Agent': userAgent },\n });\n\n if (response.ok) {\n robotsPresent = true;\n const content = await response.text();\n\n if (content && discoveredLocales.size > 0) {\n const disallowedPaths = content\n .split('\\n')\n .map((line) => line.trim().toLowerCase())\n .filter((line) => line.startsWith('disallow:'))\n .map((line) => line.slice('disallow:'.length).trim());\n\n for (const locale of discoveredLocales) {\n for (const path of disallowedPaths) {\n if (path === `/${locale}` || path === `/${locale}/`) {\n noLocalizedUrlsForgotten = false;\n errors.push(\n `Locale path \"${locale}\" appears to be blocked in robots.txt: ${path}`\n );\n }\n }\n }\n }\n }\n } catch (error) {\n errors.push(\n `Failed to fetch robots.txt: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n\n events.push({\n type: 'robots_robotsPresent',\n status: robotsPresent ? 'success' : 'warning',\n details: {\n warning: robotsPresent ? undefined : 'No robots.txt found',\n error: errors.length > 0 ? errors : undefined,\n },\n });\n\n if (robotsPresent) {\n events.push({\n type: 'robots_noLocalizedUrlsForgotten',\n status: noLocalizedUrlsForgotten ? 'success' : 'error',\n details: { error: noLocalizedUrlsForgotten ? undefined : errors },\n });\n }\n};\n\n/** Fetch and check `sitemap.xml`, emitting sitemap-related events. */\nexport const checkSitemap = async (\n origin: string,\n discoveredLocales: Set<string>,\n userAgent: string,\n events: ScanEvent[]\n): Promise<void> => {\n let sitemapPresent = false;\n let hasXDefault = false;\n let hasAlternates = false;\n let noLocalizedUrlsForgotten = true;\n const errors: string[] = [];\n\n try {\n const response = await fetch(`${origin}/sitemap.xml`, {\n headers: { 'User-Agent': userAgent },\n });\n\n if (response.ok) {\n sitemapPresent = true;\n const content = await response.text();\n\n const hreflangMatches = content.match(/hreflang\\s*=\\s*\"([^\"]+)\"/gi) ?? [];\n const hreflangs = hreflangMatches.map((m) =>\n m.replace(/hreflang\\s*=\\s*\"/i, '').replace(/\"$/, '')\n );\n hasAlternates = hreflangs.length > 0;\n hasXDefault = hreflangs.includes('x-default');\n\n if (discoveredLocales.size > 0) {\n const urlBlocks = content.match(/<url\\b[\\s\\S]*?<\\/url>/gi) ?? [];\n const allFoundLocales = new Set<string>();\n let anyUrlMissingLocale = false;\n\n for (const block of urlBlocks) {\n const localesInUrl = new Set<string>();\n\n for (const hreflang of block.match(/hreflang\\s*=\\s*\"([^\"]+)\"/gi) ??\n []) {\n const value = hreflang\n .replace(/hreflang\\s*=\\s*\"/i, '')\n .replace(/\"$/, '');\n if (value !== 'x-default') {\n localesInUrl.add(value);\n allFoundLocales.add(value);\n }\n }\n\n const loc = block.match(/<loc>([\\s\\S]*?)<\\/loc>/i)?.[1]?.trim();\n if (loc) {\n try {\n const firstSegment = new URL(loc).pathname\n .split('/')\n .filter(Boolean)[0];\n if (firstSegment && discoveredLocales.has(firstSegment)) {\n localesInUrl.add(firstSegment);\n allFoundLocales.add(firstSegment);\n }\n } catch {\n /* invalid loc URL, skip */\n }\n }\n\n const missing = [...discoveredLocales].filter(\n (locale) => !localesInUrl.has(locale)\n );\n if (missing.length > 0 && missing.length < discoveredLocales.size) {\n anyUrlMissingLocale = true;\n }\n }\n\n const completelyMissing = [...discoveredLocales].filter(\n (locale) => !allFoundLocales.has(locale)\n );\n if (anyUrlMissingLocale || completelyMissing.length > 0) {\n noLocalizedUrlsForgotten = false;\n if (completelyMissing.length > 0) {\n errors.push(\n `The following locales are completely missing from the sitemap: ${completelyMissing.join(', ')}`\n );\n }\n }\n }\n }\n } catch (error) {\n errors.push(\n `Failed to fetch sitemap.xml: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n\n events.push({\n type: 'sitemap_sitemapPresent',\n status: sitemapPresent ? 'success' : 'warning',\n details: {\n warning: sitemapPresent ? undefined : 'No sitemap.xml found',\n error: errors.length > 0 ? errors : undefined,\n },\n });\n\n if (sitemapPresent) {\n events.push({\n type: 'sitemap_noLocalizedUrlsForgotten',\n status: noLocalizedUrlsForgotten ? 'success' : 'warning',\n details: { warning: noLocalizedUrlsForgotten ? undefined : errors },\n });\n\n events.push({\n type: 'sitemap_hasXDefault',\n status: hasXDefault ? 'success' : 'warning',\n details: {\n warning: hasXDefault ? undefined : 'No x-default hreflang in sitemap',\n },\n });\n\n events.push({\n type: 'sitemap_hasAlternates',\n status: hasAlternates ? 'success' : 'warning',\n details: {\n warning: hasAlternates\n ? undefined\n : 'No alternate language links found in sitemap',\n },\n });\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"checks.cjs","names":["extractHtmlLang","extractHtmlDir","hasCanonical","extractHreflangs","ALL_LOCALES","analyzeBundleContent"],"sources":["../../../src/scan/checks.ts"],"sourcesContent":["import { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport { analyzeBundleContent } from './analyzeBundleContent';\nimport {\n type Anchor,\n extractHreflangs,\n extractHtmlDir,\n extractHtmlLang,\n hasCanonical,\n} from './parseHtml';\nimport type {\n BundleChunkInput,\n BundleContentAnalysis,\n ScanEvent,\n} from './types';\n\n/** Format a byte count as a human-readable size. */\nexport const formatSize = (bytes: number): string => {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(2)} KB`;\n return `${bytes} B`;\n};\n\n/**\n * Check the `<html>` element attributes (`lang`, `dir`) and the resulting\n * current-locale signal. Returns the detected language tag.\n */\nexport const checkHtmlAttributes = (\n html: string,\n targetUrl: string,\n events: ScanEvent[]\n): { langTag: string | undefined } => {\n const langTag = extractHtmlLang(html);\n const dirTag = extractHtmlDir(html);\n\n events.push({\n type: `url_htmlLang\\\\${targetUrl}`,\n status: langTag ? 'success' : 'error',\n details: {\n success: langTag,\n error: langTag ? undefined : 'Missing html lang attribute',\n },\n });\n\n events.push({\n type: `url_currentLocale\\\\${targetUrl}`,\n status: langTag ? 'success' : 'warning',\n details: {\n success: langTag,\n warning: langTag ? undefined : 'No locale detected',\n },\n });\n\n events.push({\n type: `url_htmlDir\\\\${targetUrl}`,\n status: dirTag ? 'success' : 'warning',\n details: {\n success: dirTag,\n warning: dirTag ? undefined : 'Missing html dir attribute',\n },\n });\n\n return { langTag };\n};\n\n/** Check the presence of a canonical link. */\nexport const checkCanonical = (\n html: string,\n targetUrl: string,\n events: ScanEvent[]\n): void => {\n const present = hasCanonical(html);\n events.push({\n type: `url_hasCanonical\\\\${targetUrl}`,\n status: present ? 'success' : 'warning',\n details: { warning: present ? undefined : 'Missing canonical link' },\n });\n};\n\n/**\n * Check the page's hreflang structure and collect discovered locales into\n * `localesSet`.\n */\nexport const checkLinguisticStructure = (\n html: string,\n targetUrl: string,\n localesSet: Set<string>,\n events: ScanEvent[]\n): void => {\n const langTag = extractHtmlLang(html);\n if (langTag) localesSet.add(langTag);\n\n const hreflangs = extractHreflangs(html);\n for (const { hreflang } of hreflangs) {\n if (hreflang !== 'x-default') localesSet.add(hreflang);\n }\n\n const hasXDefault = hreflangs.some((h) => h.hreflang === 'x-default');\n\n events.push({\n type: `url_hreflang\\\\${targetUrl}`,\n status: hreflangs.length > 0 ? 'success' : 'warning',\n details: {\n success: hreflangs.length > 0 ? hreflangs : undefined,\n warning: hreflangs.length === 0 ? 'No hreflang tags found' : undefined,\n },\n });\n\n events.push({\n type: `url_hasXDefault\\\\${targetUrl}`,\n status: hasXDefault ? 'success' : 'error',\n details: {\n error: hasXDefault ? undefined : 'Missing x-default hreflang link',\n },\n });\n};\n\nconst normalizeHost = (host: string): string =>\n host.startsWith('www.') ? host.slice(4) : host;\n\nconst localeValues = Object.values(ALL_LOCALES) as string[];\n\n/**\n * Check whether internal links carry a locale segment, mirroring the hosted\n * audit's URL-structure analysis but operating on parsed anchors instead of a\n * live DOM.\n */\nexport const checkUrlStructure = (\n anchors: Anchor[],\n origin: string,\n targetUrl: string,\n events: ScanEvent[]\n): void => {\n const targetHostname = normalizeHost(new URL(origin).hostname);\n\n let localizedCount = 0;\n let totalInternalCount = 0;\n const nonLocalizedLinks: string[] = [];\n\n for (const { href } of anchors) {\n if (!href || href.startsWith('#') || href.startsWith('javascript:'))\n continue;\n\n try {\n const url = new URL(href, origin);\n if (normalizeHost(url.hostname) !== targetHostname) continue;\n\n totalInternalCount++;\n const path = url.pathname.toLowerCase();\n const hostname = url.hostname.toLowerCase();\n\n const hasLocaleInPath = localeValues.some((locale) => {\n const l = locale.toLowerCase();\n return path === `/${l}` || path.includes(`/${l}/`);\n });\n const hasLocaleInSubdomain = localeValues.some((locale) => {\n const l = locale.toLowerCase();\n return hostname.startsWith(`${l}.`) || hostname.includes(`.${l}.`);\n });\n\n if (hasLocaleInPath || hasLocaleInSubdomain) {\n localizedCount++;\n } else {\n nonLocalizedLinks.push(href);\n }\n } catch {\n /* ignore malformed URLs */\n }\n }\n\n const hasLocalizedLinks = localizedCount > 0;\n const allAnchorsLocalized =\n totalInternalCount === 0 || localizedCount === totalInternalCount;\n\n events.push({\n type: `url_hasLocalizedLinks\\\\${targetUrl}`,\n status: hasLocalizedLinks ? 'success' : 'warning',\n details: {\n success: hasLocalizedLinks\n ? `${localizedCount} localized links found out of ${totalInternalCount} internal links`\n : undefined,\n warning: hasLocalizedLinks ? undefined : 'No localized links found',\n },\n });\n\n events.push({\n type: `url_allAnchorsLocalized\\\\${targetUrl}`,\n status: allAnchorsLocalized ? 'success' : 'warning',\n details: {\n warning: allAnchorsLocalized\n ? undefined\n : {\n message: 'Some internal links are not localized',\n links: nonLocalizedLinks,\n },\n },\n });\n};\n\n/**\n * Analyze the JavaScript bundles for unused locale content and emit the\n * corresponding event. Returns the analysis so callers can report on it.\n */\nexport const checkBundleContent = (\n chunks: BundleChunkInput[],\n html: string,\n currentLocale: string | undefined,\n targetUrl: string,\n totalPageSize: number,\n events: ScanEvent[]\n): BundleContentAnalysis | undefined => {\n if (!currentLocale) {\n events.push({\n type: `url_unusedBundleContent\\\\${targetUrl}`,\n status: 'warning',\n details: {\n warning: 'Cannot analyse bundle content: page locale not detected',\n },\n });\n return undefined;\n }\n\n const analysis = analyzeBundleContent(\n chunks,\n html,\n currentLocale,\n totalPageSize\n );\n\n // Status is driven by the main bundle — lazy chunks with unused content are expected.\n const mainBundleMaxUnused = analysis.mainBundleChunks.reduce(\n (max, c) => Math.max(max, c.unusedPercent),\n 0\n );\n\n const status =\n mainBundleMaxUnused === 0\n ? 'success'\n : mainBundleMaxUnused <= 30\n ? 'warning'\n : 'error';\n\n events.push({\n type: `url_unusedBundleContent\\\\${targetUrl}`,\n status,\n details: { [status]: analysis },\n });\n\n return analysis;\n};\n\n/** Fetch and check `robots.txt`, emitting robots-related events. */\nexport const checkRobots = async (\n origin: string,\n discoveredLocales: Set<string>,\n userAgent: string,\n events: ScanEvent[]\n): Promise<void> => {\n let robotsPresent = false;\n let noLocalizedUrlsForgotten = true;\n const errors: string[] = [];\n\n try {\n const response = await fetch(`${origin}/robots.txt`, {\n headers: { 'User-Agent': userAgent },\n });\n\n if (response.ok) {\n robotsPresent = true;\n const content = await response.text();\n\n if (content && discoveredLocales.size > 0) {\n const disallowedPaths = content\n .split('\\n')\n .map((line) => line.trim().toLowerCase())\n .filter((line) => line.startsWith('disallow:'))\n .map((line) => line.slice('disallow:'.length).trim());\n\n for (const locale of discoveredLocales) {\n for (const path of disallowedPaths) {\n if (path === `/${locale}` || path === `/${locale}/`) {\n noLocalizedUrlsForgotten = false;\n errors.push(\n `Locale path \"${locale}\" appears to be blocked in robots.txt: ${path}`\n );\n }\n }\n }\n }\n }\n } catch (error) {\n errors.push(\n `Failed to fetch robots.txt: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n\n events.push({\n type: 'robots_robotsPresent',\n status: robotsPresent ? 'success' : 'warning',\n details: {\n warning: robotsPresent ? undefined : 'No robots.txt found',\n error: errors.length > 0 ? errors : undefined,\n },\n });\n\n if (robotsPresent) {\n events.push({\n type: 'robots_noLocalizedUrlsForgotten',\n status: noLocalizedUrlsForgotten ? 'success' : 'error',\n details: { error: noLocalizedUrlsForgotten ? undefined : errors },\n });\n }\n};\n\n/** Fetch and check `sitemap.xml`, emitting sitemap-related events. */\nexport const checkSitemap = async (\n origin: string,\n discoveredLocales: Set<string>,\n userAgent: string,\n events: ScanEvent[]\n): Promise<void> => {\n let sitemapPresent = false;\n let hasXDefault = false;\n let hasAlternates = false;\n let noLocalizedUrlsForgotten = true;\n const errors: string[] = [];\n\n try {\n const response = await fetch(`${origin}/sitemap.xml`, {\n headers: { 'User-Agent': userAgent },\n });\n\n if (response.ok) {\n sitemapPresent = true;\n const content = await response.text();\n\n const hreflangMatches = content.match(/hreflang\\s*=\\s*\"([^\"]+)\"/gi) ?? [];\n const hreflangs = hreflangMatches.map((m) =>\n m.replace(/hreflang\\s*=\\s*\"/i, '').replace(/\"$/, '')\n );\n hasAlternates = hreflangs.length > 0;\n hasXDefault = hreflangs.includes('x-default');\n\n if (discoveredLocales.size > 0) {\n const urlBlocks = content.match(/<url\\b[\\s\\S]*?<\\/url>/gi) ?? [];\n const allFoundLocales = new Set<string>();\n let anyUrlMissingLocale = false;\n\n for (const block of urlBlocks) {\n const localesInUrl = new Set<string>();\n\n for (const hreflang of block.match(/hreflang\\s*=\\s*\"([^\"]+)\"/gi) ??\n []) {\n const value = hreflang\n .replace(/hreflang\\s*=\\s*\"/i, '')\n .replace(/\"$/, '');\n if (value !== 'x-default') {\n localesInUrl.add(value);\n allFoundLocales.add(value);\n }\n }\n\n const loc = block.match(/<loc>([\\s\\S]*?)<\\/loc>/i)?.[1]?.trim();\n if (loc) {\n try {\n const firstSegment = new URL(loc).pathname\n .split('/')\n .filter(Boolean)[0];\n if (firstSegment && discoveredLocales.has(firstSegment)) {\n localesInUrl.add(firstSegment);\n allFoundLocales.add(firstSegment);\n }\n } catch {\n /* invalid loc URL, skip */\n }\n }\n\n const missing = [...discoveredLocales].filter(\n (locale) => !localesInUrl.has(locale)\n );\n if (missing.length > 0 && missing.length < discoveredLocales.size) {\n anyUrlMissingLocale = true;\n }\n }\n\n const completelyMissing = [...discoveredLocales].filter(\n (locale) => !allFoundLocales.has(locale)\n );\n if (anyUrlMissingLocale || completelyMissing.length > 0) {\n noLocalizedUrlsForgotten = false;\n if (completelyMissing.length > 0) {\n errors.push(\n `The following locales are completely missing from the sitemap: ${completelyMissing.join(', ')}`\n );\n }\n }\n }\n }\n } catch (error) {\n errors.push(\n `Failed to fetch sitemap.xml: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n\n events.push({\n type: 'sitemap_sitemapPresent',\n status: sitemapPresent ? 'success' : 'warning',\n details: {\n warning: sitemapPresent ? undefined : 'No sitemap.xml found',\n error: errors.length > 0 ? errors : undefined,\n },\n });\n\n if (sitemapPresent) {\n events.push({\n type: 'sitemap_noLocalizedUrlsForgotten',\n status: noLocalizedUrlsForgotten ? 'success' : 'warning',\n details: { warning: noLocalizedUrlsForgotten ? undefined : errors },\n });\n\n events.push({\n type: 'sitemap_hasXDefault',\n status: hasXDefault ? 'success' : 'warning',\n details: {\n warning: hasXDefault ? undefined : 'No x-default hreflang in sitemap',\n },\n });\n\n events.push({\n type: 'sitemap_hasAlternates',\n status: hasAlternates ? 'success' : 'warning',\n details: {\n warning: hasAlternates\n ? undefined\n : 'No alternate language links found in sitemap',\n },\n });\n }\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"parseHtml.cjs","names":[],"sources":["../../../src/scan/parseHtml.ts"],"sourcesContent":["/**\n * Tiny dependency-free HTML extraction helpers.\n *\n * The hosted backend audit relies on Cheerio + a real browser, but the CLI scan\n * must stay dependency-light. These regex-based helpers cover the handful of\n * head/anchor signals the score needs. They are intentionally forgiving: when a\n * tag can't be parsed it is simply skipped rather than throwing.\n */\n\n/** Compute the UTF-8 byte length of a string in both Node and browser builds. */\nexport const byteLength = (text: string): number =>\n typeof Buffer !== 'undefined'\n ? Buffer.byteLength(text, 'utf-8')\n : new TextEncoder().encode(text).length;\n\n/** Read an attribute value off a single tag's attribute string. */\nconst readAttribute = (\n attributes: string,\n attributeName: string\n): string | undefined => {\n const match = attributes.match(\n new RegExp(`${attributeName}\\\\s*=\\\\s*(\"([^\"]*)\"|'([^']*)'|([^\\\\s>]+))`, 'i')\n );\n if (!match) return undefined;\n return match[2] ?? match[3] ?? match[4];\n};\n\n/** Extract the `lang` attribute of the `<html>` element, if present. */\nexport const extractHtmlLang = (html: string): string | undefined => {\n const htmlTag = html.match(/<html\\b([^>]*)>/i);\n return htmlTag ? readAttribute(htmlTag[1], 'lang') : undefined;\n};\n\n/** Extract the `dir` attribute of the `<html>` element, if present. */\nexport const extractHtmlDir = (html: string): string | undefined => {\n const htmlTag = html.match(/<html\\b([^>]*)>/i);\n return htmlTag ? readAttribute(htmlTag[1], 'dir') : undefined;\n};\n\n/** Extract the document `<title>` text. */\nexport const extractTitle = (html: string): string => {\n const match = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i);\n return match ? match[1].trim() : '';\n};\n\n/** Extract the `<meta name=\"description\">` content. */\nexport const extractMetaDescription = (html: string): string => {\n const metas = html.match(/<meta\\b[^>]*>/gi) ?? [];\n for (const meta of metas) {\n if (/name\\s*=\\s*(\"|')?description\\1?/i.test(meta)) {\n return readAttribute(meta, 'content') ?? '';\n }\n }\n return '';\n};\n\n/** Extract the `<meta property=\"og:image\">` content. */\nexport const extractOgImage = (html: string): string | undefined => {\n const metas = html.match(/<meta\\b[^>]*>/gi) ?? [];\n for (const meta of metas) {\n if (/property\\s*=\\s*(\"|')?og:image\\1?/i.test(meta)) {\n return readAttribute(meta, 'content');\n }\n }\n return undefined;\n};\n\n/** Whether a `<link rel=\"canonical\">` element is present. */\nexport const hasCanonical = (html: string): boolean => {\n const links = html.match(/<link\\b[^>]*>/gi) ?? [];\n return links.some((link) => /rel\\s*=\\s*(\"|')?canonical\\1?/i.test(link));\n};\n\n/** A parsed `<link rel=\"alternate\" hreflang>` element. */\nexport type HreflangLink = { hreflang: string; href: string };\n\n/** Extract every `<link rel=\"alternate\" hreflang=\"…\" href=\"…\">` element. */\nexport const extractHreflangs = (html: string): HreflangLink[] => {\n const links = html.match(/<link\\b[^>]*>/gi) ?? [];\n const result: HreflangLink[] = [];\n for (const link of links) {\n if (!/rel\\s*=\\s*(\"|')?alternate\\1?/i.test(link)) continue;\n const hreflang = readAttribute(link, 'hreflang');\n const href = readAttribute(link, 'href');\n if (hreflang && href) result.push({ hreflang, href });\n }\n return result;\n};\n\n/**\n * Extract every eagerly-loaded script URL: `<script src>`,\n * `<link rel=\"modulepreload\">` and `<link rel=\"preload\" as=\"script\">`.\n *\n * @param html - The raw HTML document.\n * @param baseUrl - Base URL used to resolve relative script URLs.\n * @returns Absolute, de-duplicated script URLs.\n */\nexport const extractScriptUrls = (html: string, baseUrl: string): string[] => {\n const urls = new Set<string>();\n\n const add = (raw: string | undefined) => {\n if (!raw) return;\n try {\n urls.add(new URL(raw, baseUrl).href);\n } catch {\n /* ignore malformed URLs */\n }\n };\n\n for (const script of html.match(/<script\\b[^>]*>/gi) ?? []) {\n add(readAttribute(script, 'src'));\n }\n\n for (const link of html.match(/<link\\b[^>]*>/gi) ?? []) {\n const rel = readAttribute(link, 'rel')?.toLowerCase();\n const as = readAttribute(link, 'as')?.toLowerCase();\n if (rel === 'modulepreload' || (rel === 'preload' && as === 'script')) {\n add(readAttribute(link, 'href'));\n }\n }\n\n return Array.from(urls);\n};\n\n/** A parsed `<a href>` anchor. */\nexport type Anchor = { href: string; text: string };\n\n/** Extract every `<a href=\"…\">text</a>` anchor from the document. */\nexport const extractAnchors = (html: string): Anchor[] => {\n const anchors: Anchor[] = [];\n const anchorPattern = /<a\\b([^>]*)>([\\s\\S]*?)<\\/a>/gi;\n let match = anchorPattern.exec(html);\n while (match !== null) {\n const href = readAttribute(match[1], 'href');\n if (href) {\n const text = match[2]\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n anchors.push({ href, text });\n }\n match = anchorPattern.exec(html);\n }\n return anchors;\n};\n\n/**\n * Extract visible text snippets from an HTML document (scripts, styles and\n * tags stripped). Used to approximate the rendered content size without a DOM.\n */\nexport const extractVisibleTextStrings = (html: string): string[] => {\n const withoutNonVisible = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ');\n\n return withoutNonVisible\n .replace(/<[^>]+>/g, '\\n')\n .split('\\n')\n .map((line) => line.replace(/\\s+/g, ' ').trim())\n .filter((line) => line.length > 1);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"parseHtml.cjs","names":[],"sources":["../../../src/scan/parseHtml.ts"],"sourcesContent":["/**\n * Tiny dependency-free HTML extraction helpers.\n *\n * The hosted backend audit relies on Cheerio + a real browser, but the CLI scan\n * must stay dependency-light. These regex-based helpers cover the handful of\n * head/anchor signals the score needs. They are intentionally forgiving: when a\n * tag can't be parsed it is simply skipped rather than throwing.\n */\n\n/** Compute the UTF-8 byte length of a string in both Node and browser builds. */\nexport const byteLength = (text: string): number =>\n typeof Buffer !== 'undefined'\n ? Buffer.byteLength(text, 'utf-8')\n : new TextEncoder().encode(text).length;\n\n/** Read an attribute value off a single tag's attribute string. */\nconst readAttribute = (\n attributes: string,\n attributeName: string\n): string | undefined => {\n const match = attributes.match(\n new RegExp(`${attributeName}\\\\s*=\\\\s*(\"([^\"]*)\"|'([^']*)'|([^\\\\s>]+))`, 'i')\n );\n if (!match) return undefined;\n return match[2] ?? match[3] ?? match[4];\n};\n\n/** Extract the `lang` attribute of the `<html>` element, if present. */\nexport const extractHtmlLang = (html: string): string | undefined => {\n const htmlTag = html.match(/<html\\b([^>]*)>/i);\n return htmlTag ? readAttribute(htmlTag[1], 'lang') : undefined;\n};\n\n/** Extract the `dir` attribute of the `<html>` element, if present. */\nexport const extractHtmlDir = (html: string): string | undefined => {\n const htmlTag = html.match(/<html\\b([^>]*)>/i);\n return htmlTag ? readAttribute(htmlTag[1], 'dir') : undefined;\n};\n\n/** Extract the document `<title>` text. */\nexport const extractTitle = (html: string): string => {\n const match = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i);\n return match ? match[1].trim() : '';\n};\n\n/** Extract the `<meta name=\"description\">` content. */\nexport const extractMetaDescription = (html: string): string => {\n const metas = html.match(/<meta\\b[^>]*>/gi) ?? [];\n for (const meta of metas) {\n if (/name\\s*=\\s*(\"|')?description\\1?/i.test(meta)) {\n return readAttribute(meta, 'content') ?? '';\n }\n }\n return '';\n};\n\n/** Extract the `<meta property=\"og:image\">` content. */\nexport const extractOgImage = (html: string): string | undefined => {\n const metas = html.match(/<meta\\b[^>]*>/gi) ?? [];\n for (const meta of metas) {\n if (/property\\s*=\\s*(\"|')?og:image\\1?/i.test(meta)) {\n return readAttribute(meta, 'content');\n }\n }\n return undefined;\n};\n\n/** Whether a `<link rel=\"canonical\">` element is present. */\nexport const hasCanonical = (html: string): boolean => {\n const links = html.match(/<link\\b[^>]*>/gi) ?? [];\n return links.some((link) => /rel\\s*=\\s*(\"|')?canonical\\1?/i.test(link));\n};\n\n/** A parsed `<link rel=\"alternate\" hreflang>` element. */\nexport type HreflangLink = { hreflang: string; href: string };\n\n/** Extract every `<link rel=\"alternate\" hreflang=\"…\" href=\"…\">` element. */\nexport const extractHreflangs = (html: string): HreflangLink[] => {\n const links = html.match(/<link\\b[^>]*>/gi) ?? [];\n const result: HreflangLink[] = [];\n for (const link of links) {\n if (!/rel\\s*=\\s*(\"|')?alternate\\1?/i.test(link)) continue;\n const hreflang = readAttribute(link, 'hreflang');\n const href = readAttribute(link, 'href');\n if (hreflang && href) result.push({ hreflang, href });\n }\n return result;\n};\n\n/**\n * Extract every eagerly-loaded script URL: `<script src>`,\n * `<link rel=\"modulepreload\">` and `<link rel=\"preload\" as=\"script\">`.\n *\n * @param html - The raw HTML document.\n * @param baseUrl - Base URL used to resolve relative script URLs.\n * @returns Absolute, de-duplicated script URLs.\n */\nexport const extractScriptUrls = (html: string, baseUrl: string): string[] => {\n const urls = new Set<string>();\n\n const add = (raw: string | undefined) => {\n if (!raw) return;\n try {\n urls.add(new URL(raw, baseUrl).href);\n } catch {\n /* ignore malformed URLs */\n }\n };\n\n for (const script of html.match(/<script\\b[^>]*>/gi) ?? []) {\n add(readAttribute(script, 'src'));\n }\n\n for (const link of html.match(/<link\\b[^>]*>/gi) ?? []) {\n const rel = readAttribute(link, 'rel')?.toLowerCase();\n const as = readAttribute(link, 'as')?.toLowerCase();\n if (rel === 'modulepreload' || (rel === 'preload' && as === 'script')) {\n add(readAttribute(link, 'href'));\n }\n }\n\n return Array.from(urls);\n};\n\n/** A parsed `<a href>` anchor. */\nexport type Anchor = { href: string; text: string };\n\n/** Extract every `<a href=\"…\">text</a>` anchor from the document. */\nexport const extractAnchors = (html: string): Anchor[] => {\n const anchors: Anchor[] = [];\n const anchorPattern = /<a\\b([^>]*)>([\\s\\S]*?)<\\/a>/gi;\n let match = anchorPattern.exec(html);\n while (match !== null) {\n const href = readAttribute(match[1], 'href');\n if (href) {\n const text = match[2]\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n anchors.push({ href, text });\n }\n match = anchorPattern.exec(html);\n }\n return anchors;\n};\n\n/**\n * Extract visible text snippets from an HTML document (scripts, styles and\n * tags stripped). Used to approximate the rendered content size without a DOM.\n */\nexport const extractVisibleTextStrings = (html: string): string[] => {\n const withoutNonVisible = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ');\n\n return withoutNonVisible\n .replace(/<[^>]+>/g, '\\n')\n .split('\\n')\n .map((line) => line.replace(/\\s+/g, ' ').trim())\n .filter((line) => line.length > 1);\n};\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
2
  const require_scan_calculateScore = require('./calculateScore.cjs');
4
3
  const require_scan_parseHtml = require('./parseHtml.cjs');
5
4
  const require_scan_checks = require('./checks.cjs');
@@ -169,7 +168,8 @@ const scanWebsite = async (targetUrl, options = {}) => {
169
168
  if (deep) logDeepScanRecommendation();
170
169
  const { html: fetchedHtml, finalUrl } = await fetchHtml(targetUrl, userAgent, timeoutMs);
171
170
  html = fetchedHtml;
172
- const { chunks: fetchedChunks, scriptBytes } = await fetchScripts(require_scan_parseHtml.extractScriptUrls(fetchedHtml, finalUrl), origin, userAgent);
171
+ const scriptUrls = require_scan_parseHtml.extractScriptUrls(fetchedHtml, finalUrl);
172
+ const { chunks: fetchedChunks, scriptBytes } = await fetchScripts(scriptUrls, origin, userAgent);
173
173
  chunks = fetchedChunks;
174
174
  totalPageSize = require_scan_parseHtml.byteLength(fetchedHtml) + scriptBytes;
175
175
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scanWebsite.cjs","names":["GREY","GREY_LIGHT","extractScriptUrls","byteLength","checkHtmlAttributes","extractAnchors","checkBundleContent","checkRobots","checkSitemap","mutateScore","toScorePercent"],"sources":["../../../src/scan/scanWebsite.ts"],"sourcesContent":["import { GREY, GREY_LIGHT } from '@intlayer/config/colors';\nimport { colorize, logger } from '@intlayer/config/logger';\nimport { mutateScore, type Score, toScorePercent } from './calculateScore';\nimport {\n checkBundleContent,\n checkCanonical,\n checkHtmlAttributes,\n checkLinguisticStructure,\n checkRobots,\n checkSitemap,\n checkUrlStructure,\n} from './checks';\nimport { byteLength, extractAnchors, extractScriptUrls } from './parseHtml';\nimport type {\n BundleChunkInput,\n ScanEvent,\n ScanOptions,\n ScanResult,\n} from './types';\n\nconst DEFAULT_USER_AGENT =\n 'Mozilla/5.0 (compatible; IntlayerScanBot/1.0; +https://intlayer.org)';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Log a recommendation to install `puppeteer` for a deeper scan. Mirrors the\n * style used by other optional-dependency hints across the CLI.\n */\nconst logDeepScanRecommendation = (): void => {\n logger([\n colorize('Recommended: Install', GREY),\n colorize('puppeteer', GREY_LIGHT),\n colorize(\n 'package to enable a deeper scan (renders client-side content & lazy-loaded chunks). See documentation:',\n GREY\n ),\n colorize('https://intlayer.org/doc/concept/cli#scan', GREY_LIGHT),\n ]);\n};\n\n/** Outcome of a render-based deep scan. */\ntype DeepScanResult = {\n html: string;\n totalPageSize: number;\n chunks: BundleChunkInput[];\n};\n\n/**\n * Render the page with a locally installed `puppeteer` to capture\n * client-rendered content, the accurate transfer size, and lazy-loaded chunks.\n *\n * `puppeteer` is imported dynamically through a non-literal specifier so it is\n * never bundled and stays an optional dependency: when it is absent the import\n * rejects and the caller falls back to the basic scan.\n *\n * @returns The deep-scan result, or `null` when `puppeteer` is unavailable.\n */\nconst runDeepScan = async (\n targetUrl: string,\n userAgent: string,\n timeoutMs: number\n): Promise<DeepScanResult | null> => {\n const moduleName = 'puppeteer';\n // Optional dependency resolved at runtime — typed as `any` because it is not\n // a declared dependency of this package.\n let puppeteer: any;\n try {\n const mod: any = await import(moduleName);\n puppeteer = mod.default ?? mod;\n } catch {\n return null;\n }\n\n let browser: any;\n try {\n browser = await puppeteer.launch({\n headless: true,\n executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,\n args: [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n '--disable-gpu',\n ],\n });\n\n const page = await browser.newPage();\n await page.setUserAgent(userAgent);\n await page.setExtraHTTPHeaders({ 'Accept-Language': 'en-US,en;q=0.9' });\n\n const origin = new URL(targetUrl).origin;\n const jsResponseMap = new Map<string, string>();\n let totalPageSize = 0;\n const pendingResponses: Promise<void>[] = [];\n\n page.on('response', (response: any) => {\n pendingResponses.push(\n (async () => {\n try {\n if (response.status() !== 200) return;\n const buffer = await response.buffer();\n totalPageSize += buffer.length;\n\n const responseUrl: string = response.url();\n const contentType: string =\n response.headers()['content-type'] ?? '';\n const isJavaScript =\n contentType.includes('javascript') ||\n /\\.(js|mjs|cjs)(\\?|$)/.test(responseUrl);\n if (isJavaScript && responseUrl.startsWith(origin)) {\n jsResponseMap.set(responseUrl, buffer.toString('utf-8'));\n }\n } catch {\n /* response already consumed or aborted */\n }\n })()\n );\n });\n\n await page.goto(targetUrl, {\n waitUntil: 'domcontentloaded',\n timeout: timeoutMs,\n });\n await page\n .waitForNetworkIdle({ idleTime: 1000, timeout: 10_000 })\n .catch(() => {\n /* ok if it never fully idles */\n });\n await Promise.allSettled(pendingResponses);\n\n const html: string = await page.content();\n const mainBundleUrls = new Set(extractScriptUrls(html, targetUrl));\n const chunks: BundleChunkInput[] = Array.from(jsResponseMap.entries()).map(\n ([url, content]) => ({\n url,\n isMainBundle: mainBundleUrls.has(url),\n content,\n })\n );\n\n return { html, totalPageSize, chunks };\n } finally {\n if (browser) await browser.close();\n }\n};\n\n/** Fetch the raw HTML document, measuring its byte size. */\nconst fetchHtml = async (\n url: string,\n userAgent: string,\n timeoutMs: number\n): Promise<{ html: string; finalUrl: string }> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n headers: { 'User-Agent': userAgent, 'Accept-Language': 'en-US,en;q=0.9' },\n signal: controller.signal,\n });\n const html = await response.text();\n return { html, finalUrl: response.url || url };\n } finally {\n clearTimeout(timer);\n }\n};\n\n/**\n * Fetch every eagerly-loaded script. Same-origin scripts keep their content so\n * their locale weight can be analyzed; third-party scripts only contribute to\n * the measured page size (their locale-like keys cause false positives).\n */\nconst fetchScripts = async (\n scriptUrls: string[],\n origin: string,\n userAgent: string\n): Promise<{ chunks: BundleChunkInput[]; scriptBytes: number }> => {\n const chunks: BundleChunkInput[] = [];\n let scriptBytes = 0;\n\n await Promise.all(\n scriptUrls.map(async (scriptUrl) => {\n try {\n const response = await fetch(scriptUrl, {\n headers: { 'User-Agent': userAgent },\n });\n if (!response.ok) return;\n const content = await response.text();\n scriptBytes += byteLength(content);\n if (scriptUrl.startsWith(origin)) {\n chunks.push({ url: scriptUrl, isMainBundle: true, content });\n }\n } catch {\n /* ignore unreachable scripts */\n }\n })\n );\n\n return { chunks, scriptBytes };\n};\n\n/**\n * Scan a single web page for i18n/SEO health and bundle weight.\n *\n * In `deep` mode (default) the page is rendered with a locally installed\n * `puppeteer`; when `puppeteer` is missing the scan transparently falls back to\n * a `basic` fetch-based pass and logs a recommendation to install it.\n *\n * @param targetUrl - The absolute URL to scan.\n * @param options - {@link ScanOptions} controlling depth, timeout and UA.\n * @returns The {@link ScanResult} including score, page size and per-check events.\n */\nexport const scanWebsite = async (\n targetUrl: string,\n options: ScanOptions = {}\n): Promise<ScanResult> => {\n const {\n deep = true,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n userAgent = DEFAULT_USER_AGENT,\n } = options;\n\n const origin = new URL(targetUrl).origin;\n\n let mode: ScanResult['mode'] = 'basic';\n let html: string;\n let totalPageSize: number;\n let chunks: BundleChunkInput[];\n\n const deepResult = deep\n ? await runDeepScan(targetUrl, userAgent, timeoutMs)\n : null;\n\n if (deepResult) {\n mode = 'deep';\n html = deepResult.html;\n chunks = deepResult.chunks;\n totalPageSize = deepResult.totalPageSize;\n } else {\n if (deep) logDeepScanRecommendation();\n const { html: fetchedHtml, finalUrl } = await fetchHtml(\n targetUrl,\n userAgent,\n timeoutMs\n );\n html = fetchedHtml;\n const scriptUrls = extractScriptUrls(fetchedHtml, finalUrl);\n const { chunks: fetchedChunks, scriptBytes } = await fetchScripts(\n scriptUrls,\n origin,\n userAgent\n );\n chunks = fetchedChunks;\n totalPageSize = byteLength(fetchedHtml) + scriptBytes;\n }\n\n const htmlSize = byteLength(html);\n\n const events: ScanEvent[] = [];\n const localesSet = new Set<string>();\n\n const { langTag } = checkHtmlAttributes(html, targetUrl, events);\n checkCanonical(html, targetUrl, events);\n checkLinguisticStructure(html, targetUrl, localesSet, events);\n checkUrlStructure(extractAnchors(html), origin, targetUrl, events);\n const bundle = checkBundleContent(\n chunks,\n html,\n langTag,\n targetUrl,\n totalPageSize,\n events\n );\n await checkRobots(origin, localesSet, userAgent, events);\n await checkSitemap(origin, localesSet, userAgent, events);\n\n const rawScore = events.reduce<Score>(\n (score, event) => mutateScore(score, event),\n { score: 0, totalScore: 0 }\n );\n\n return {\n url: targetUrl,\n mode,\n totalPageSize,\n htmlSize,\n score: toScorePercent(rawScore),\n rawScore,\n events,\n locales: Array.from(localesSet),\n bundle,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"scanWebsite.cjs","names":["GREY","GREY_LIGHT","extractScriptUrls","byteLength","checkHtmlAttributes","extractAnchors","checkBundleContent","checkRobots","checkSitemap","mutateScore","toScorePercent"],"sources":["../../../src/scan/scanWebsite.ts"],"sourcesContent":["import { GREY, GREY_LIGHT } from '@intlayer/config/colors';\nimport { colorize, logger } from '@intlayer/config/logger';\nimport { mutateScore, type Score, toScorePercent } from './calculateScore';\nimport {\n checkBundleContent,\n checkCanonical,\n checkHtmlAttributes,\n checkLinguisticStructure,\n checkRobots,\n checkSitemap,\n checkUrlStructure,\n} from './checks';\nimport { byteLength, extractAnchors, extractScriptUrls } from './parseHtml';\nimport type {\n BundleChunkInput,\n ScanEvent,\n ScanOptions,\n ScanResult,\n} from './types';\n\nconst DEFAULT_USER_AGENT =\n 'Mozilla/5.0 (compatible; IntlayerScanBot/1.0; +https://intlayer.org)';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Log a recommendation to install `puppeteer` for a deeper scan. Mirrors the\n * style used by other optional-dependency hints across the CLI.\n */\nconst logDeepScanRecommendation = (): void => {\n logger([\n colorize('Recommended: Install', GREY),\n colorize('puppeteer', GREY_LIGHT),\n colorize(\n 'package to enable a deeper scan (renders client-side content & lazy-loaded chunks). See documentation:',\n GREY\n ),\n colorize('https://intlayer.org/doc/concept/cli#scan', GREY_LIGHT),\n ]);\n};\n\n/** Outcome of a render-based deep scan. */\ntype DeepScanResult = {\n html: string;\n totalPageSize: number;\n chunks: BundleChunkInput[];\n};\n\n/**\n * Render the page with a locally installed `puppeteer` to capture\n * client-rendered content, the accurate transfer size, and lazy-loaded chunks.\n *\n * `puppeteer` is imported dynamically through a non-literal specifier so it is\n * never bundled and stays an optional dependency: when it is absent the import\n * rejects and the caller falls back to the basic scan.\n *\n * @returns The deep-scan result, or `null` when `puppeteer` is unavailable.\n */\nconst runDeepScan = async (\n targetUrl: string,\n userAgent: string,\n timeoutMs: number\n): Promise<DeepScanResult | null> => {\n const moduleName = 'puppeteer';\n // Optional dependency resolved at runtime — typed as `any` because it is not\n // a declared dependency of this package.\n let puppeteer: any;\n try {\n const mod: any = await import(moduleName);\n puppeteer = mod.default ?? mod;\n } catch {\n return null;\n }\n\n let browser: any;\n try {\n browser = await puppeteer.launch({\n headless: true,\n executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,\n args: [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n '--disable-gpu',\n ],\n });\n\n const page = await browser.newPage();\n await page.setUserAgent(userAgent);\n await page.setExtraHTTPHeaders({ 'Accept-Language': 'en-US,en;q=0.9' });\n\n const origin = new URL(targetUrl).origin;\n const jsResponseMap = new Map<string, string>();\n let totalPageSize = 0;\n const pendingResponses: Promise<void>[] = [];\n\n page.on('response', (response: any) => {\n pendingResponses.push(\n (async () => {\n try {\n if (response.status() !== 200) return;\n const buffer = await response.buffer();\n totalPageSize += buffer.length;\n\n const responseUrl: string = response.url();\n const contentType: string =\n response.headers()['content-type'] ?? '';\n const isJavaScript =\n contentType.includes('javascript') ||\n /\\.(js|mjs|cjs)(\\?|$)/.test(responseUrl);\n if (isJavaScript && responseUrl.startsWith(origin)) {\n jsResponseMap.set(responseUrl, buffer.toString('utf-8'));\n }\n } catch {\n /* response already consumed or aborted */\n }\n })()\n );\n });\n\n await page.goto(targetUrl, {\n waitUntil: 'domcontentloaded',\n timeout: timeoutMs,\n });\n await page\n .waitForNetworkIdle({ idleTime: 1000, timeout: 10_000 })\n .catch(() => {\n /* ok if it never fully idles */\n });\n await Promise.allSettled(pendingResponses);\n\n const html: string = await page.content();\n const mainBundleUrls = new Set(extractScriptUrls(html, targetUrl));\n const chunks: BundleChunkInput[] = Array.from(jsResponseMap.entries()).map(\n ([url, content]) => ({\n url,\n isMainBundle: mainBundleUrls.has(url),\n content,\n })\n );\n\n return { html, totalPageSize, chunks };\n } finally {\n if (browser) await browser.close();\n }\n};\n\n/** Fetch the raw HTML document, measuring its byte size. */\nconst fetchHtml = async (\n url: string,\n userAgent: string,\n timeoutMs: number\n): Promise<{ html: string; finalUrl: string }> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n headers: { 'User-Agent': userAgent, 'Accept-Language': 'en-US,en;q=0.9' },\n signal: controller.signal,\n });\n const html = await response.text();\n return { html, finalUrl: response.url || url };\n } finally {\n clearTimeout(timer);\n }\n};\n\n/**\n * Fetch every eagerly-loaded script. Same-origin scripts keep their content so\n * their locale weight can be analyzed; third-party scripts only contribute to\n * the measured page size (their locale-like keys cause false positives).\n */\nconst fetchScripts = async (\n scriptUrls: string[],\n origin: string,\n userAgent: string\n): Promise<{ chunks: BundleChunkInput[]; scriptBytes: number }> => {\n const chunks: BundleChunkInput[] = [];\n let scriptBytes = 0;\n\n await Promise.all(\n scriptUrls.map(async (scriptUrl) => {\n try {\n const response = await fetch(scriptUrl, {\n headers: { 'User-Agent': userAgent },\n });\n if (!response.ok) return;\n const content = await response.text();\n scriptBytes += byteLength(content);\n if (scriptUrl.startsWith(origin)) {\n chunks.push({ url: scriptUrl, isMainBundle: true, content });\n }\n } catch {\n /* ignore unreachable scripts */\n }\n })\n );\n\n return { chunks, scriptBytes };\n};\n\n/**\n * Scan a single web page for i18n/SEO health and bundle weight.\n *\n * In `deep` mode (default) the page is rendered with a locally installed\n * `puppeteer`; when `puppeteer` is missing the scan transparently falls back to\n * a `basic` fetch-based pass and logs a recommendation to install it.\n *\n * @param targetUrl - The absolute URL to scan.\n * @param options - {@link ScanOptions} controlling depth, timeout and UA.\n * @returns The {@link ScanResult} including score, page size and per-check events.\n */\nexport const scanWebsite = async (\n targetUrl: string,\n options: ScanOptions = {}\n): Promise<ScanResult> => {\n const {\n deep = true,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n userAgent = DEFAULT_USER_AGENT,\n } = options;\n\n const origin = new URL(targetUrl).origin;\n\n let mode: ScanResult['mode'] = 'basic';\n let html: string;\n let totalPageSize: number;\n let chunks: BundleChunkInput[];\n\n const deepResult = deep\n ? await runDeepScan(targetUrl, userAgent, timeoutMs)\n : null;\n\n if (deepResult) {\n mode = 'deep';\n html = deepResult.html;\n chunks = deepResult.chunks;\n totalPageSize = deepResult.totalPageSize;\n } else {\n if (deep) logDeepScanRecommendation();\n const { html: fetchedHtml, finalUrl } = await fetchHtml(\n targetUrl,\n userAgent,\n timeoutMs\n );\n html = fetchedHtml;\n const scriptUrls = extractScriptUrls(fetchedHtml, finalUrl);\n const { chunks: fetchedChunks, scriptBytes } = await fetchScripts(\n scriptUrls,\n origin,\n userAgent\n );\n chunks = fetchedChunks;\n totalPageSize = byteLength(fetchedHtml) + scriptBytes;\n }\n\n const htmlSize = byteLength(html);\n\n const events: ScanEvent[] = [];\n const localesSet = new Set<string>();\n\n const { langTag } = checkHtmlAttributes(html, targetUrl, events);\n checkCanonical(html, targetUrl, events);\n checkLinguisticStructure(html, targetUrl, localesSet, events);\n checkUrlStructure(extractAnchors(html), origin, targetUrl, events);\n const bundle = checkBundleContent(\n chunks,\n html,\n langTag,\n targetUrl,\n totalPageSize,\n events\n );\n await checkRobots(origin, localesSet, userAgent, events);\n await checkSitemap(origin, localesSet, userAgent, events);\n\n const rawScore = events.reduce<Score>(\n (score, event) => mutateScore(score, event),\n { score: 0, totalScore: 0 }\n );\n\n return {\n url: targetUrl,\n mode,\n totalPageSize,\n htmlSize,\n score: toScorePercent(rawScore),\n rawScore,\n events,\n locales: Array.from(localesSet),\n bundle,\n };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"createFileAdapter.cjs","names":["buildFilePathPatternContext","extractKeyAndLocaleFromPath","writeFileIfChanged"],"sources":["../../../src/syncPluginKit/createFileAdapter.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { parseFilePathPattern } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport fg from 'fast-glob';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { extractKeyAndLocaleFromPath } from './extractKeyAndLocaleFromPath';\nimport { buildFilePathPatternContext } from './filePathPatternHelpers';\nimport type {\n ContentAdapter,\n ContentEntry,\n FormatCodec,\n SyncContent,\n SyncPluginContext,\n} from './types';\n\n/**\n * Discovery strategy of the file adapter:\n * - `strict`: keep only files whose path rebuilds identically from the source\n * pattern, and fabricate entries for missing locales/keys so every declared\n * locale has a write-back target (sync plugins).\n * - `inclusive`: keep every glob match without fabricating missing entries\n * (read-only load plugins, whose patterns may contain free `**` globs).\n */\nexport type FileAdapterDiscovery = 'strict' | 'inclusive';\n\nexport type CreateFileAdapterOptions = {\n /**\n * Location of the files, as a static string, a templated string\n * (e.g. `./messages/{{locale}}/{{key}}.json`) or a function building the\n * path from the key and locale.\n */\n source: FilePathPattern;\n\n /**\n * Format of the files: string payload ↔ structured content.\n */\n codec: FormatCodec;\n\n /**\n * Optional override of how one file is read and parsed. Defaults to a plain\n * utf-8 read followed by `codec.parse`, returning `undefined` for missing or\n * unreadable files. Adapters needing richer loading (e.g. JSON5 or\n * transpiled TS sources) provide their own implementation here.\n */\n readEntry?: (\n absoluteFilePath: string,\n context: SyncPluginContext\n ) => Promise<SyncContent | undefined>;\n\n /**\n * Discovery strategy. Defaults to `'strict'`.\n */\n discovery?: FileAdapterDiscovery;\n};\n\ntype FilePath = string;\ntype MessagesRecord = Record<Locale, Record<string, FilePath>>;\n\n/**\n * Create a filesystem {@link ContentAdapter} for `createSyncPlugin`.\n *\n * Handles glob discovery of the source pattern, key/locale extraction from\n * paths, base-directory resolution, and change-detected atomic writes.\n */\nexport const createFileAdapter = (\n options: CreateFileAdapterOptions\n): ContentAdapter => {\n const { source, codec, discovery = 'strict' } = options;\n const readEntry = options.readEntry ?? createFileReader(codec.parse);\n\n let patternMarkerPromise: Promise<string> | undefined;\n\n /**\n * Source pattern with `{{key}}` / `{{locale}}` markers kept verbatim,\n * memoized because pattern functions can be asynchronous.\n */\n const getPatternMarker = () => {\n patternMarkerPromise ??= parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{key}}', '{{locale}}')\n );\n\n return patternMarkerPromise;\n };\n\n const listMessages = async (\n context: SyncPluginContext\n ): Promise<MessagesRecord> => {\n const { system, internationalization } = context.configuration;\n const { baseDir } = system;\n const { locales } = internationalization;\n\n const result: MessagesRecord = {} as MessagesRecord;\n\n for (const locale of locales) {\n const globPatternLocale = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('**', locale)\n );\n\n const maskPatternLocale = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{__KEY__}}', locale)\n );\n\n if (!globPatternLocale || !maskPatternLocale) {\n continue;\n }\n\n const normalizedGlobPattern = globPatternLocale.startsWith('./')\n ? globPatternLocale.slice(2)\n : globPatternLocale;\n\n const files = await fg(normalizedGlobPattern, {\n cwd: baseDir,\n });\n\n const hasLocaleInMask = maskPatternLocale.includes('{{__LOCALE__}}');\n const hasKeyInMask = maskPatternLocale.includes('{{__KEY__}}');\n\n for (const file of files) {\n let key: string;\n let extractedLocale: Locale;\n\n if (hasLocaleInMask || hasKeyInMask) {\n const extraction = extractKeyAndLocaleFromPath(\n file,\n maskPatternLocale,\n locales,\n locale\n );\n\n if (!extraction) {\n continue;\n }\n\n key = extraction.key;\n extractedLocale = extraction.locale;\n } else if (discovery === 'inclusive') {\n // Mask has no placeholders — the file was found via a concrete\n // locale glob. Attribute it directly to the current loop locale.\n key = 'index';\n extractedLocale = locale;\n } else {\n // Strict mode relies on the fabrication step below to attribute\n // placeholder-free sources to their canonical paths.\n continue;\n }\n\n const absoluteFoundPath = isAbsolute(file)\n ? file\n : resolve(baseDir, file);\n\n if (discovery === 'strict') {\n // Rebuild what the path SHOULD be for this key/locale. A mismatch\n // means the file belongs to another plugin/structure.\n const expectedPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, extractedLocale)\n );\n\n const absoluteExpectedPath = isAbsolute(expectedPath)\n ? expectedPath\n : resolve(baseDir, expectedPath);\n\n if (absoluteFoundPath !== absoluteExpectedPath) {\n continue;\n }\n }\n\n result[extractedLocale] ??= {};\n result[extractedLocale][key] = absoluteFoundPath;\n }\n }\n\n if (discovery === 'inclusive') {\n // Read-only mode only uses actual discovered files; do not fabricate\n // missing locales or keys, since no outputs are written.\n return result;\n }\n\n // Ensure all declared locales are present even if the file doesn't exist yet\n const maskWithKey = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{__KEY__}}', locales[0])\n );\n\n const hasKeyInMask = maskWithKey.includes('{{__KEY__}}');\n const discoveredKeys = new Set<string>();\n\n for (const locale of Object.keys(result) as Locale[]) {\n for (const key of Object.keys(result[locale] ?? {})) {\n discoveredKeys.add(key);\n }\n }\n\n if (!hasKeyInMask) {\n discoveredKeys.add('index');\n }\n\n for (const locale of locales) {\n result[locale] ??= {};\n\n for (const key of discoveredKeys) {\n if (!result[locale][key]) {\n const builtPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n result[locale][key] = isAbsolute(builtPath)\n ? builtPath\n : resolve(baseDir, builtPath);\n }\n }\n }\n\n return result;\n };\n\n return {\n list: async (context) => {\n const messages = await listMessages(context);\n\n const entries: ContentEntry[] = (\n Object.entries(messages) as [Locale, Record<string, FilePath>][]\n ).flatMap(([locale, keysRecord]) =>\n Object.entries(keysRecord).map(([key, absoluteFilePath]) => ({\n key,\n locale,\n uri: absoluteFilePath,\n filePath: absoluteFilePath,\n }))\n );\n\n return entries;\n },\n\n read: async (entry, context) => await readEntry(entry.uri, context),\n\n write: async ({ key, locale }, content, { configuration }) => {\n const builderPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n const absoluteFilePath = resolve(\n configuration.system.baseDir,\n builderPath\n );\n\n await mkdir(dirname(absoluteFilePath), { recursive: true });\n\n await writeFileIfChanged(\n absoluteFilePath,\n codec.serialize(content, { locale }),\n { tempDir: configuration.system?.tempDir }\n );\n },\n\n resolveUri: async ({ key, locale }, { configuration }) => {\n const builderPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n return resolve(configuration.system.baseDir, builderPath);\n },\n\n getFillPattern: async () => await getPatternMarker(),\n\n describeSource: async () => await getPatternMarker(),\n\n detectSplitKeys: async () =>\n !(await getPatternMarker()).includes('{{key}}'),\n };\n};\n\n/**\n * Default `readEntry` implementation: plain utf-8 read followed by the given\n * parser. Returns `undefined` for missing or unreadable files.\n */\nexport const createFileReader =\n (parse: (raw: string) => SyncContent) =>\n async (absoluteFilePath: string): Promise<SyncContent | undefined> => {\n try {\n const raw = await readFile(absoluteFilePath, 'utf-8');\n\n return parse(raw);\n } catch {\n return undefined;\n }\n };\n"],"mappings":"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"}
1
+ {"version":3,"file":"createFileAdapter.cjs","names":["buildFilePathPatternContext","extractKeyAndLocaleFromPath","writeFileIfChanged"],"sources":["../../../src/syncPluginKit/createFileAdapter.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { parseFilePathPattern } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport fg from 'fast-glob';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { extractKeyAndLocaleFromPath } from './extractKeyAndLocaleFromPath';\nimport { buildFilePathPatternContext } from './filePathPatternHelpers';\nimport type {\n ContentAdapter,\n ContentEntry,\n FormatCodec,\n SyncContent,\n SyncPluginContext,\n} from './types';\n\n/**\n * Discovery strategy of the file adapter:\n * - `strict`: keep only files whose path rebuilds identically from the source\n * pattern, and fabricate entries for missing locales/keys so every declared\n * locale has a write-back target (sync plugins).\n * - `inclusive`: keep every glob match without fabricating missing entries\n * (read-only load plugins, whose patterns may contain free `**` globs).\n */\nexport type FileAdapterDiscovery = 'strict' | 'inclusive';\n\nexport type CreateFileAdapterOptions = {\n /**\n * Location of the files, as a static string, a templated string\n * (e.g. `./messages/{{locale}}/{{key}}.json`) or a function building the\n * path from the key and locale.\n */\n source: FilePathPattern;\n\n /**\n * Format of the files: string payload ↔ structured content.\n */\n codec: FormatCodec;\n\n /**\n * Optional override of how one file is read and parsed. Defaults to a plain\n * utf-8 read followed by `codec.parse`, returning `undefined` for missing or\n * unreadable files. Adapters needing richer loading (e.g. JSON5 or\n * transpiled TS sources) provide their own implementation here.\n */\n readEntry?: (\n absoluteFilePath: string,\n context: SyncPluginContext\n ) => Promise<SyncContent | undefined>;\n\n /**\n * Discovery strategy. Defaults to `'strict'`.\n */\n discovery?: FileAdapterDiscovery;\n};\n\ntype FilePath = string;\ntype MessagesRecord = Record<Locale, Record<string, FilePath>>;\n\n/**\n * Create a filesystem {@link ContentAdapter} for `createSyncPlugin`.\n *\n * Handles glob discovery of the source pattern, key/locale extraction from\n * paths, base-directory resolution, and change-detected atomic writes.\n */\nexport const createFileAdapter = (\n options: CreateFileAdapterOptions\n): ContentAdapter => {\n const { source, codec, discovery = 'strict' } = options;\n const readEntry = options.readEntry ?? createFileReader(codec.parse);\n\n let patternMarkerPromise: Promise<string> | undefined;\n\n /**\n * Source pattern with `{{key}}` / `{{locale}}` markers kept verbatim,\n * memoized because pattern functions can be asynchronous.\n */\n const getPatternMarker = () => {\n patternMarkerPromise ??= parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{key}}', '{{locale}}')\n );\n\n return patternMarkerPromise;\n };\n\n const listMessages = async (\n context: SyncPluginContext\n ): Promise<MessagesRecord> => {\n const { system, internationalization } = context.configuration;\n const { baseDir } = system;\n const { locales } = internationalization;\n\n const result: MessagesRecord = {} as MessagesRecord;\n\n for (const locale of locales) {\n const globPatternLocale = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('**', locale)\n );\n\n const maskPatternLocale = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{__KEY__}}', locale)\n );\n\n if (!globPatternLocale || !maskPatternLocale) {\n continue;\n }\n\n const normalizedGlobPattern = globPatternLocale.startsWith('./')\n ? globPatternLocale.slice(2)\n : globPatternLocale;\n\n const files = await fg(normalizedGlobPattern, {\n cwd: baseDir,\n });\n\n const hasLocaleInMask = maskPatternLocale.includes('{{__LOCALE__}}');\n const hasKeyInMask = maskPatternLocale.includes('{{__KEY__}}');\n\n for (const file of files) {\n let key: string;\n let extractedLocale: Locale;\n\n if (hasLocaleInMask || hasKeyInMask) {\n const extraction = extractKeyAndLocaleFromPath(\n file,\n maskPatternLocale,\n locales,\n locale\n );\n\n if (!extraction) {\n continue;\n }\n\n key = extraction.key;\n extractedLocale = extraction.locale;\n } else if (discovery === 'inclusive') {\n // Mask has no placeholders — the file was found via a concrete\n // locale glob. Attribute it directly to the current loop locale.\n key = 'index';\n extractedLocale = locale;\n } else {\n // Strict mode relies on the fabrication step below to attribute\n // placeholder-free sources to their canonical paths.\n continue;\n }\n\n const absoluteFoundPath = isAbsolute(file)\n ? file\n : resolve(baseDir, file);\n\n if (discovery === 'strict') {\n // Rebuild what the path SHOULD be for this key/locale. A mismatch\n // means the file belongs to another plugin/structure.\n const expectedPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, extractedLocale)\n );\n\n const absoluteExpectedPath = isAbsolute(expectedPath)\n ? expectedPath\n : resolve(baseDir, expectedPath);\n\n if (absoluteFoundPath !== absoluteExpectedPath) {\n continue;\n }\n }\n\n result[extractedLocale] ??= {};\n result[extractedLocale][key] = absoluteFoundPath;\n }\n }\n\n if (discovery === 'inclusive') {\n // Read-only mode only uses actual discovered files; do not fabricate\n // missing locales or keys, since no outputs are written.\n return result;\n }\n\n // Ensure all declared locales are present even if the file doesn't exist yet\n const maskWithKey = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{__KEY__}}', locales[0])\n );\n\n const hasKeyInMask = maskWithKey.includes('{{__KEY__}}');\n const discoveredKeys = new Set<string>();\n\n for (const locale of Object.keys(result) as Locale[]) {\n for (const key of Object.keys(result[locale] ?? {})) {\n discoveredKeys.add(key);\n }\n }\n\n if (!hasKeyInMask) {\n discoveredKeys.add('index');\n }\n\n for (const locale of locales) {\n result[locale] ??= {};\n\n for (const key of discoveredKeys) {\n if (!result[locale][key]) {\n const builtPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n result[locale][key] = isAbsolute(builtPath)\n ? builtPath\n : resolve(baseDir, builtPath);\n }\n }\n }\n\n return result;\n };\n\n return {\n list: async (context) => {\n const messages = await listMessages(context);\n\n const entries: ContentEntry[] = (\n Object.entries(messages) as [Locale, Record<string, FilePath>][]\n ).flatMap(([locale, keysRecord]) =>\n Object.entries(keysRecord).map(([key, absoluteFilePath]) => ({\n key,\n locale,\n uri: absoluteFilePath,\n filePath: absoluteFilePath,\n }))\n );\n\n return entries;\n },\n\n read: async (entry, context) => await readEntry(entry.uri, context),\n\n write: async ({ key, locale }, content, { configuration }) => {\n const builderPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n const absoluteFilePath = resolve(\n configuration.system.baseDir,\n builderPath\n );\n\n await mkdir(dirname(absoluteFilePath), { recursive: true });\n\n await writeFileIfChanged(\n absoluteFilePath,\n codec.serialize(content, { locale }),\n { tempDir: configuration.system?.tempDir }\n );\n },\n\n resolveUri: async ({ key, locale }, { configuration }) => {\n const builderPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n return resolve(configuration.system.baseDir, builderPath);\n },\n\n getFillPattern: async () => await getPatternMarker(),\n\n describeSource: async () => await getPatternMarker(),\n\n detectSplitKeys: async () =>\n !(await getPatternMarker()).includes('{{key}}'),\n };\n};\n\n/**\n * Default `readEntry` implementation: plain utf-8 read followed by the given\n * parser. Returns `undefined` for missing or unreadable files.\n */\nexport const createFileReader =\n (parse: (raw: string) => SyncContent) =>\n async (absoluteFilePath: string): Promise<SyncContent | undefined> => {\n try {\n const raw = await readFile(absoluteFilePath, 'utf-8');\n\n return parse(raw);\n } catch {\n return undefined;\n }\n };\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
2
  let node_path = require("node:path");
4
3
  let _intlayer_config_logger = require("@intlayer/config/logger");
5
4
 
@@ -39,7 +38,10 @@ const createSyncPlugin = (options) => {
39
38
  const context = { configuration };
40
39
  const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
41
40
  const entries = await adapter.list(context);
42
- if (entries.length === 0) appLogger(`[${name}] No dictionaries found at locations matching source pattern: ${(0, _intlayer_config_logger.colorizePath)(await adapter.describeSource?.(context) ?? name)}`, { level: "warn" });
41
+ if (entries.length === 0) {
42
+ const sourceDescription = await adapter.describeSource?.(context) ?? name;
43
+ appLogger(`[${name}] No dictionaries found at locations matching source pattern: ${(0, _intlayer_config_logger.colorizePath)(sourceDescription)}`, { level: "warn" });
44
+ }
43
45
  const shouldSplitByKeys = await resolveSplitKeys();
44
46
  const { baseDir } = configuration.system;
45
47
  const { defaultLocale } = configuration.internationalization;
@@ -114,7 +116,8 @@ const createSyncPlugin = (options) => {
114
116
  const mergedContentByLocale = {};
115
117
  const writeKeyByLocale = {};
116
118
  for (const { key, dictionary } of ownedDictionaries) for (const locale of locales) {
117
- const content = toPlainContent(formatDictionaryOutput(getPerLocaleDictionary(dictionary, locale), format).content);
119
+ const formattedOutput = formatDictionaryOutput(getPerLocaleDictionary(dictionary, locale), format);
120
+ const content = toPlainContent(formattedOutput.content);
118
121
  if (isEmptyContent(content)) continue;
119
122
  mergedContentByLocale[locale] ??= {};
120
123
  mergedContentByLocale[locale][key] = content;
@@ -133,7 +136,9 @@ const createSyncPlugin = (options) => {
133
136
  dictionary,
134
137
  locale
135
138
  }))), async ({ key, dictionary, locale }) => {
136
- const content = toPlainContent(formatDictionaryOutput(getPerLocaleDictionary(dictionary, locale), format).content);
139
+ const localizedDictionary = getPerLocaleDictionary(dictionary, locale);
140
+ const formattedOutput = formatDictionaryOutput(localizedDictionary, format);
141
+ const content = toPlainContent(formattedOutput.content);
137
142
  if (isEmptyContent(content)) return;
138
143
  await adapter.write({
139
144
  key,
@@ -1 +1 @@
1
- {"version":3,"file":"createSyncPlugin.cjs","names":[],"sources":["../../../src/syncPluginKit/createSyncPlugin.ts"],"sourcesContent":["import { relative, resolve } from 'node:path';\nimport { colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { Dictionary, LocalDictionaryId } from '@intlayer/types/dictionary';\nimport type { Plugin } from '@intlayer/types/plugin';\nimport type {\n CreateSyncPluginOptions,\n SyncContent,\n SyncPluginContext,\n} from './types';\n\n/**\n * Content that carries nothing to persist: `undefined`, `null`, or an object\n * without any own key. Writing it back would erase the target.\n */\nconst isEmptyContent = (content: unknown): boolean =>\n typeof content === 'undefined' ||\n content === null ||\n (typeof content === 'object' && Object.keys(content).length === 0);\n\n/**\n * Deep-clone formatted output into plain JSON data, stripping prototypes and\n * non-serializable values before the emptiness check and the write.\n */\nconst toPlainContent = (content: unknown): unknown =>\n typeof content === 'undefined'\n ? undefined\n : JSON.parse(JSON.stringify(content));\n\n/**\n * Build an Intlayer {@link Plugin} from a transport adapter.\n *\n * The factory implements the three plugin hooks once — ingestion\n * (`loadDictionaries`), content-declaration reformatting (`formatOutput`) and\n * write-back (`afterBuild`) — so adapters only describe *where* content lives\n * (filesystem, TMS such as Crowdin, extra CMS…) and codecs only describe the\n * payload format. Write-back only processes dictionaries whose `location`\n * matches this plugin instance, so adapters never see foreign content.\n */\nexport const createSyncPlugin = (options: CreateSyncPluginOptions): Plugin => {\n const {\n name,\n adapter,\n direction = 'both',\n location,\n priority = 0,\n format,\n localeOverride,\n } = options;\n\n let splitKeysPromise: Promise<boolean> | undefined;\n\n /**\n * `splitKeys` resolution is asynchronous (adapter auto-detection may parse\n * an async source pattern), so it is resolved lazily and memoized.\n */\n const resolveSplitKeys = (): Promise<boolean> => {\n splitKeysPromise ??= (async () =>\n options.splitKeys ?? (await adapter.detectSplitKeys?.()) ?? false)();\n\n return splitKeysPromise;\n };\n\n const loadDictionaries: Plugin['loadDictionaries'] = async ({\n configuration,\n }) => {\n const context: SyncPluginContext = { configuration };\n const appLogger = getAppLogger(configuration);\n\n const entries = await adapter.list(context);\n\n if (entries.length === 0) {\n const sourceDescription =\n (await adapter.describeSource?.(context)) ?? name;\n\n appLogger(\n `[${name}] No dictionaries found at locations matching source pattern: ${colorizePath(sourceDescription)}`,\n { level: 'warn' }\n );\n }\n\n const shouldSplitByKeys = await resolveSplitKeys();\n const { baseDir } = configuration.system;\n const { defaultLocale } = configuration.internationalization;\n\n // Sync plugins advertise the source pattern (with {{key}}/{{locale}}\n // markers) as fill target; pull-only plugins fill each entry in place.\n let patternFill: string | undefined;\n\n if (direction === 'both' && adapter.getFillPattern) {\n const fillPattern = await adapter.getFillPattern(context);\n patternFill = relative(baseDir, resolve(baseDir, fillPattern));\n }\n\n const dictionaries: Dictionary[] = [];\n\n for (const entry of entries) {\n const content = (await adapter.read(entry, context)) ?? {};\n\n const relativeFilePath = entry.filePath\n ? relative(baseDir, entry.filePath)\n : undefined;\n\n const usedLocale = (localeOverride ?? entry.locale) as Locale;\n const filled = usedLocale !== defaultLocale ? true : undefined;\n const fill = patternFill ?? relativeFilePath;\n const identifier = relativeFilePath ?? entry.uri;\n\n // One entry groups several namespaces by its first-level keys: emit one\n // dictionary per top-level key (e.g. `Hero`, `Nav`, …).\n if (shouldSplitByKeys) {\n for (const [namespaceKey, namespaceContent] of Object.entries(\n content\n )) {\n dictionaries.push({\n key: namespaceKey,\n locale: usedLocale,\n fill,\n format,\n localId:\n `${namespaceKey}::${location}::${identifier}` as LocalDictionaryId,\n location: location as Dictionary['location'],\n filled,\n content: namespaceContent as SyncContent,\n filePath: relativeFilePath,\n priority,\n } as Dictionary);\n }\n continue;\n }\n\n dictionaries.push({\n key: entry.key,\n locale: usedLocale,\n fill,\n format,\n localId:\n `${entry.key}::${location}::${identifier}` as LocalDictionaryId,\n location: location as Dictionary['location'],\n filled,\n content,\n filePath: relativeFilePath,\n priority,\n } as Dictionary);\n }\n\n return dictionaries;\n };\n\n if (direction === 'pull') {\n return { name, loadDictionaries };\n }\n\n const formatOutput: Plugin['formatOutput'] = async ({\n dictionary,\n configuration,\n }) => {\n if (!dictionary.filePath || !dictionary.locale) return dictionary;\n\n // In split mode several namespaces share the same target; the target is\n // re-assembled in `afterBuild`. Skip here to avoid overwriting the whole\n // target with a single namespace.\n if (await resolveSplitKeys()) return dictionary;\n\n // Ownership check: only reformat declarations this adapter can identify\n // as its own canonical target.\n if (!adapter.resolveUri) return dictionary;\n\n const canonicalUri = await adapter.resolveUri(\n { key: dictionary.key, locale: dictionary.locale as Locale },\n { configuration }\n );\n\n const { baseDir } = configuration.system;\n\n if (\n resolve(baseDir, canonicalUri) !== resolve(baseDir, dictionary.filePath)\n ) {\n return dictionary;\n }\n\n // Lazy import to keep the module graph light when configs are transpiled\n const { formatDictionaryOutput } = await import('../formatDictionary');\n\n return formatDictionaryOutput(dictionary as Dictionary, format).content;\n };\n\n const afterBuild: Plugin['afterBuild'] = async ({\n dictionaries,\n configuration,\n }) => {\n // Lazy imports to keep the module graph light when configs are transpiled\n const { getPerLocaleDictionary } = await import('@intlayer/core/plugins');\n const { formatDictionaryOutput } = await import('../formatDictionary');\n const { parallelize } = await import('../utils/parallelize');\n\n const context: SyncPluginContext = { configuration };\n const { locales } = configuration.internationalization;\n\n // Only ever hand the adapter dictionaries owned by THIS plugin instance.\n const ownedDictionaries = Object.entries(dictionaries.mergedDictionaries)\n .map(([key, result]) => ({\n key,\n dictionary: result.dictionary as Dictionary,\n }))\n .filter(({ dictionary }) => dictionary.location === location);\n\n if (await resolveSplitKeys()) {\n // Split mode: every namespace dictionary writes back into the same\n // per-locale target. Re-assemble them under their top-level key and\n // write each target once, instead of one write per key (which would\n // overwrite).\n const mergedContentByLocale = {} as Record<Locale, SyncContent>;\n const writeKeyByLocale = {} as Record<Locale, string>;\n\n for (const { key, dictionary } of ownedDictionaries) {\n for (const locale of locales) {\n const localizedDictionary = getPerLocaleDictionary(\n dictionary,\n locale\n );\n\n const formattedOutput = formatDictionaryOutput(\n localizedDictionary,\n format\n );\n\n const content = toPlainContent(formattedOutput.content);\n\n if (isEmptyContent(content)) continue;\n\n mergedContentByLocale[locale] ??= {};\n mergedContentByLocale[locale][key] = content;\n writeKeyByLocale[locale] = key;\n }\n }\n\n await parallelize(\n Object.keys(mergedContentByLocale) as Locale[],\n async (locale) => {\n await adapter.write(\n { key: writeKeyByLocale[locale], locale },\n mergedContentByLocale[locale],\n context\n );\n }\n );\n\n return;\n }\n\n const writeTasks = ownedDictionaries.flatMap(({ key, dictionary }) =>\n locales.map((locale) => ({ key, dictionary, locale }))\n );\n\n await parallelize(writeTasks, async ({ key, dictionary, locale }) => {\n const localizedDictionary = getPerLocaleDictionary(dictionary, locale);\n\n const formattedOutput = formatDictionaryOutput(\n localizedDictionary,\n format\n );\n\n const content = toPlainContent(formattedOutput.content);\n\n if (isEmptyContent(content)) return;\n\n await adapter.write({ key, locale }, content as SyncContent, context);\n });\n };\n\n return { name, loadDictionaries, formatOutput, afterBuild };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"createSyncPlugin.cjs","names":[],"sources":["../../../src/syncPluginKit/createSyncPlugin.ts"],"sourcesContent":["import { relative, resolve } from 'node:path';\nimport { colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { Dictionary, LocalDictionaryId } from '@intlayer/types/dictionary';\nimport type { Plugin } from '@intlayer/types/plugin';\nimport type {\n CreateSyncPluginOptions,\n SyncContent,\n SyncPluginContext,\n} from './types';\n\n/**\n * Content that carries nothing to persist: `undefined`, `null`, or an object\n * without any own key. Writing it back would erase the target.\n */\nconst isEmptyContent = (content: unknown): boolean =>\n typeof content === 'undefined' ||\n content === null ||\n (typeof content === 'object' && Object.keys(content).length === 0);\n\n/**\n * Deep-clone formatted output into plain JSON data, stripping prototypes and\n * non-serializable values before the emptiness check and the write.\n */\nconst toPlainContent = (content: unknown): unknown =>\n typeof content === 'undefined'\n ? undefined\n : JSON.parse(JSON.stringify(content));\n\n/**\n * Build an Intlayer {@link Plugin} from a transport adapter.\n *\n * The factory implements the three plugin hooks once — ingestion\n * (`loadDictionaries`), content-declaration reformatting (`formatOutput`) and\n * write-back (`afterBuild`) — so adapters only describe *where* content lives\n * (filesystem, TMS such as Crowdin, extra CMS…) and codecs only describe the\n * payload format. Write-back only processes dictionaries whose `location`\n * matches this plugin instance, so adapters never see foreign content.\n */\nexport const createSyncPlugin = (options: CreateSyncPluginOptions): Plugin => {\n const {\n name,\n adapter,\n direction = 'both',\n location,\n priority = 0,\n format,\n localeOverride,\n } = options;\n\n let splitKeysPromise: Promise<boolean> | undefined;\n\n /**\n * `splitKeys` resolution is asynchronous (adapter auto-detection may parse\n * an async source pattern), so it is resolved lazily and memoized.\n */\n const resolveSplitKeys = (): Promise<boolean> => {\n splitKeysPromise ??= (async () =>\n options.splitKeys ?? (await adapter.detectSplitKeys?.()) ?? false)();\n\n return splitKeysPromise;\n };\n\n const loadDictionaries: Plugin['loadDictionaries'] = async ({\n configuration,\n }) => {\n const context: SyncPluginContext = { configuration };\n const appLogger = getAppLogger(configuration);\n\n const entries = await adapter.list(context);\n\n if (entries.length === 0) {\n const sourceDescription =\n (await adapter.describeSource?.(context)) ?? name;\n\n appLogger(\n `[${name}] No dictionaries found at locations matching source pattern: ${colorizePath(sourceDescription)}`,\n { level: 'warn' }\n );\n }\n\n const shouldSplitByKeys = await resolveSplitKeys();\n const { baseDir } = configuration.system;\n const { defaultLocale } = configuration.internationalization;\n\n // Sync plugins advertise the source pattern (with {{key}}/{{locale}}\n // markers) as fill target; pull-only plugins fill each entry in place.\n let patternFill: string | undefined;\n\n if (direction === 'both' && adapter.getFillPattern) {\n const fillPattern = await adapter.getFillPattern(context);\n patternFill = relative(baseDir, resolve(baseDir, fillPattern));\n }\n\n const dictionaries: Dictionary[] = [];\n\n for (const entry of entries) {\n const content = (await adapter.read(entry, context)) ?? {};\n\n const relativeFilePath = entry.filePath\n ? relative(baseDir, entry.filePath)\n : undefined;\n\n const usedLocale = (localeOverride ?? entry.locale) as Locale;\n const filled = usedLocale !== defaultLocale ? true : undefined;\n const fill = patternFill ?? relativeFilePath;\n const identifier = relativeFilePath ?? entry.uri;\n\n // One entry groups several namespaces by its first-level keys: emit one\n // dictionary per top-level key (e.g. `Hero`, `Nav`, …).\n if (shouldSplitByKeys) {\n for (const [namespaceKey, namespaceContent] of Object.entries(\n content\n )) {\n dictionaries.push({\n key: namespaceKey,\n locale: usedLocale,\n fill,\n format,\n localId:\n `${namespaceKey}::${location}::${identifier}` as LocalDictionaryId,\n location: location as Dictionary['location'],\n filled,\n content: namespaceContent as SyncContent,\n filePath: relativeFilePath,\n priority,\n } as Dictionary);\n }\n continue;\n }\n\n dictionaries.push({\n key: entry.key,\n locale: usedLocale,\n fill,\n format,\n localId:\n `${entry.key}::${location}::${identifier}` as LocalDictionaryId,\n location: location as Dictionary['location'],\n filled,\n content,\n filePath: relativeFilePath,\n priority,\n } as Dictionary);\n }\n\n return dictionaries;\n };\n\n if (direction === 'pull') {\n return { name, loadDictionaries };\n }\n\n const formatOutput: Plugin['formatOutput'] = async ({\n dictionary,\n configuration,\n }) => {\n if (!dictionary.filePath || !dictionary.locale) return dictionary;\n\n // In split mode several namespaces share the same target; the target is\n // re-assembled in `afterBuild`. Skip here to avoid overwriting the whole\n // target with a single namespace.\n if (await resolveSplitKeys()) return dictionary;\n\n // Ownership check: only reformat declarations this adapter can identify\n // as its own canonical target.\n if (!adapter.resolveUri) return dictionary;\n\n const canonicalUri = await adapter.resolveUri(\n { key: dictionary.key, locale: dictionary.locale as Locale },\n { configuration }\n );\n\n const { baseDir } = configuration.system;\n\n if (\n resolve(baseDir, canonicalUri) !== resolve(baseDir, dictionary.filePath)\n ) {\n return dictionary;\n }\n\n // Lazy import to keep the module graph light when configs are transpiled\n const { formatDictionaryOutput } = await import('../formatDictionary');\n\n return formatDictionaryOutput(dictionary as Dictionary, format).content;\n };\n\n const afterBuild: Plugin['afterBuild'] = async ({\n dictionaries,\n configuration,\n }) => {\n // Lazy imports to keep the module graph light when configs are transpiled\n const { getPerLocaleDictionary } = await import('@intlayer/core/plugins');\n const { formatDictionaryOutput } = await import('../formatDictionary');\n const { parallelize } = await import('../utils/parallelize');\n\n const context: SyncPluginContext = { configuration };\n const { locales } = configuration.internationalization;\n\n // Only ever hand the adapter dictionaries owned by THIS plugin instance.\n const ownedDictionaries = Object.entries(dictionaries.mergedDictionaries)\n .map(([key, result]) => ({\n key,\n dictionary: result.dictionary as Dictionary,\n }))\n .filter(({ dictionary }) => dictionary.location === location);\n\n if (await resolveSplitKeys()) {\n // Split mode: every namespace dictionary writes back into the same\n // per-locale target. Re-assemble them under their top-level key and\n // write each target once, instead of one write per key (which would\n // overwrite).\n const mergedContentByLocale = {} as Record<Locale, SyncContent>;\n const writeKeyByLocale = {} as Record<Locale, string>;\n\n for (const { key, dictionary } of ownedDictionaries) {\n for (const locale of locales) {\n const localizedDictionary = getPerLocaleDictionary(\n dictionary,\n locale\n );\n\n const formattedOutput = formatDictionaryOutput(\n localizedDictionary,\n format\n );\n\n const content = toPlainContent(formattedOutput.content);\n\n if (isEmptyContent(content)) continue;\n\n mergedContentByLocale[locale] ??= {};\n mergedContentByLocale[locale][key] = content;\n writeKeyByLocale[locale] = key;\n }\n }\n\n await parallelize(\n Object.keys(mergedContentByLocale) as Locale[],\n async (locale) => {\n await adapter.write(\n { key: writeKeyByLocale[locale], locale },\n mergedContentByLocale[locale],\n context\n );\n }\n );\n\n return;\n }\n\n const writeTasks = ownedDictionaries.flatMap(({ key, dictionary }) =>\n locales.map((locale) => ({ key, dictionary, locale }))\n );\n\n await parallelize(writeTasks, async ({ key, dictionary, locale }) => {\n const localizedDictionary = getPerLocaleDictionary(dictionary, locale);\n\n const formattedOutput = formatDictionaryOutput(\n localizedDictionary,\n format\n );\n\n const content = toPlainContent(formattedOutput.content);\n\n if (isEmptyContent(content)) return;\n\n await adapter.write({ key, locale }, content as SyncContent, context);\n });\n };\n\n return { name, loadDictionaries, formatOutput, afterBuild };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"extractKeyAndLocaleFromPath.cjs","names":[],"sources":["../../../src/syncPluginKit/extractKeyAndLocaleFromPath.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\n\nconst escapeRegex = (text: string) =>\n text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Extract the dictionary key and locale of a file path by matching it against\n * a mask pattern where `{{__KEY__}}` and `{{__LOCALE__}}` mark the positions\n * of the key and locale segments.\n *\n * Returns `null` when the path does not match the mask, or when the mask\n * contains no placeholder at all (no named capture group can be produced).\n * Missing placeholders fall back to `'index'` for the key and to\n * `defaultLocale` for the locale.\n */\nexport const extractKeyAndLocaleFromPath = (\n filePath: string,\n maskPattern: string,\n locales: Locale[],\n defaultLocale: Locale\n): { key: string; locale: Locale } | null => {\n const keyPlaceholder = '{{__KEY__}}';\n const localePlaceholder = '{{__LOCALE__}}';\n\n // fast-glob strips leading \"./\" from returned paths; normalize both sides\n const normalize = (path: string) =>\n path.startsWith('./') ? path.slice(2) : path;\n\n const normalizedFilePath = normalize(filePath);\n const normalizedMask = normalize(maskPattern);\n\n const localesAlternation = locales.join('|');\n\n // Escape special regex chars, then convert glob wildcards to regex equivalents.\n // Must replace ** before * to avoid double-replacing.\n let regexString = `^${escapeRegex(normalizedMask)}$`;\n regexString = regexString.replace(/\\\\\\*\\\\\\*/g, '.*'); // ** → match any path segments\n regexString = regexString.replace(/\\\\\\*/g, '[^/]*'); // * → match within a single segment\n\n regexString = regexString.replace(\n escapeRegex(localePlaceholder),\n `(?<locale>${localesAlternation})`\n );\n\n if (normalizedMask.includes(keyPlaceholder)) {\n regexString = regexString.replace(\n escapeRegex(keyPlaceholder),\n '(?<key>.+)'\n );\n }\n\n const maskRegex = new RegExp(regexString);\n const match = maskRegex.exec(normalizedFilePath);\n\n if (!match?.groups) {\n return null;\n }\n\n const key = (match.groups.key as string | undefined) ?? 'index';\n const locale = (match.groups.locale as Locale | undefined) ?? defaultLocale;\n\n return { key, locale };\n};\n"],"mappings":";;;AAEA,MAAM,eAAe,SACnB,KAAK,QAAQ,uBAAuB,OAAO;;;;;;;;;;;AAY7C,MAAa,+BACX,UACA,aACA,SACA,kBAC2C;CAC3C,MAAM,iBAAiB;CACvB,MAAM,oBAAoB;CAG1B,MAAM,aAAa,SACjB,KAAK,WAAW,KAAK,GAAG,KAAK,MAAM,EAAE,GAAG;CAE1C,MAAM,qBAAqB,UAAU,SAAS;CAC9C,MAAM,iBAAiB,UAAU,YAAY;CAE7C,MAAM,qBAAqB,QAAQ,KAAK,IAAI;CAI5C,IAAI,cAAc,IAAI,YAAY,eAAe,CAAC;AAClD,eAAc,YAAY,QAAQ,aAAa,KAAK;AACpD,eAAc,YAAY,QAAQ,SAAS,QAAQ;AAEnD,eAAc,YAAY,QACxB,YAAY,kBAAkB,EAC9B,aAAa,mBAAmB,GACjC;AAED,KAAI,eAAe,SAAS,eAAe,CACzC,eAAc,YAAY,QACxB,YAAY,eAAe,EAC3B,aACD;CAIH,MAAM,QAAQ,IADQ,OAAO,YACN,CAAC,KAAK,mBAAmB;AAEhD,KAAI,CAAC,OAAO,OACV,QAAO;AAMT,QAAO;EAAE,KAHI,MAAM,OAAO,OAA8B;EAG1C,QAFE,MAAM,OAAO,UAAiC;EAExC"}
1
+ {"version":3,"file":"extractKeyAndLocaleFromPath.cjs","names":[],"sources":["../../../src/syncPluginKit/extractKeyAndLocaleFromPath.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\n\nconst escapeRegex = (text: string) =>\n text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Extract the dictionary key and locale of a file path by matching it against\n * a mask pattern where `{{__KEY__}}` and `{{__LOCALE__}}` mark the positions\n * of the key and locale segments.\n *\n * Returns `null` when the path does not match the mask, or when the mask\n * contains no placeholder at all (no named capture group can be produced).\n * Missing placeholders fall back to `'index'` for the key and to\n * `defaultLocale` for the locale.\n */\nexport const extractKeyAndLocaleFromPath = (\n filePath: string,\n maskPattern: string,\n locales: Locale[],\n defaultLocale: Locale\n): { key: string; locale: Locale } | null => {\n const keyPlaceholder = '{{__KEY__}}';\n const localePlaceholder = '{{__LOCALE__}}';\n\n // fast-glob strips leading \"./\" from returned paths; normalize both sides\n const normalize = (path: string) =>\n path.startsWith('./') ? path.slice(2) : path;\n\n const normalizedFilePath = normalize(filePath);\n const normalizedMask = normalize(maskPattern);\n\n const localesAlternation = locales.join('|');\n\n // Escape special regex chars, then convert glob wildcards to regex equivalents.\n // Must replace ** before * to avoid double-replacing.\n let regexString = `^${escapeRegex(normalizedMask)}$`;\n regexString = regexString.replace(/\\\\\\*\\\\\\*/g, '.*'); // ** → match any path segments\n regexString = regexString.replace(/\\\\\\*/g, '[^/]*'); // * → match within a single segment\n\n regexString = regexString.replace(\n escapeRegex(localePlaceholder),\n `(?<locale>${localesAlternation})`\n );\n\n if (normalizedMask.includes(keyPlaceholder)) {\n regexString = regexString.replace(\n escapeRegex(keyPlaceholder),\n '(?<key>.+)'\n );\n }\n\n const maskRegex = new RegExp(regexString);\n const match = maskRegex.exec(normalizedFilePath);\n\n if (!match?.groups) {\n return null;\n }\n\n const key = (match.groups.key as string | undefined) ?? 'index';\n const locale = (match.groups.locale as Locale | undefined) ?? defaultLocale;\n\n return { key, locale };\n};\n"],"mappings":";;;AAEA,MAAM,eAAe,SACnB,KAAK,QAAQ,uBAAuB,MAAM;;;;;;;;;;;AAY5C,MAAa,+BACX,UACA,aACA,SACA,kBAC2C;CAC3C,MAAM,iBAAiB;CACvB,MAAM,oBAAoB;CAG1B,MAAM,aAAa,SACjB,KAAK,WAAW,IAAI,IAAI,KAAK,MAAM,CAAC,IAAI;CAE1C,MAAM,qBAAqB,UAAU,QAAQ;CAC7C,MAAM,iBAAiB,UAAU,WAAW;CAE5C,MAAM,qBAAqB,QAAQ,KAAK,GAAG;CAI3C,IAAI,cAAc,IAAI,YAAY,cAAc,EAAE;CAClD,cAAc,YAAY,QAAQ,aAAa,IAAI;CACnD,cAAc,YAAY,QAAQ,SAAS,OAAO;CAElD,cAAc,YAAY,QACxB,YAAY,iBAAiB,GAC7B,aAAa,mBAAmB,EAClC;CAEA,IAAI,eAAe,SAAS,cAAc,GACxC,cAAc,YAAY,QACxB,YAAY,cAAc,GAC1B,YACF;CAIF,MAAM,QAAQ,IADQ,OAAO,WACP,CAAC,CAAC,KAAK,kBAAkB;CAE/C,IAAI,CAAC,OAAO,QACV,OAAO;CAMT,OAAO;EAAE,KAHI,MAAM,OAAO,OAA8B;EAG1C,QAFE,MAAM,OAAO,UAAiC;CAEzC;AACvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"filePathPatternHelpers.cjs","names":[],"sources":["../../../src/syncPluginKit/filePathPatternHelpers.ts"],"sourcesContent":["import type { FilePathPatternContext } from '@intlayer/types/filePathPattern';\n\n/**\n * Build the context handed to `parseFilePathPattern` from the only two\n * variables sync plugins resolve: the dictionary key and the locale.\n *\n * `FilePathPatternContext` declares extra fields (`fileName`, `extension`,\n * `format`…) that only apply to content-declaration paths; sync-plugin\n * patterns never reference them, so this single cast keeps the partial\n * context in one audited place instead of scattering `as any` at call sites.\n */\nexport const buildFilePathPatternContext = (\n key: string,\n locale?: string\n): FilePathPatternContext =>\n ({\n key,\n locale,\n }) as Partial<FilePathPatternContext> as FilePathPatternContext;\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,+BACX,KACA,YAEC;CACC;CACA;CACD"}
1
+ {"version":3,"file":"filePathPatternHelpers.cjs","names":[],"sources":["../../../src/syncPluginKit/filePathPatternHelpers.ts"],"sourcesContent":["import type { FilePathPatternContext } from '@intlayer/types/filePathPattern';\n\n/**\n * Build the context handed to `parseFilePathPattern` from the only two\n * variables sync plugins resolve: the dictionary key and the locale.\n *\n * `FilePathPatternContext` declares extra fields (`fileName`, `extension`,\n * `format`…) that only apply to content-declaration paths; sync-plugin\n * patterns never reference them, so this single cast keeps the partial\n * context in one audited place instead of scattering `as any` at call sites.\n */\nexport const buildFilePathPatternContext = (\n key: string,\n locale?: string\n): FilePathPatternContext =>\n ({\n key,\n locale,\n }) as Partial<FilePathPatternContext> as FilePathPatternContext;\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,+BACX,KACA,YAEC;CACC;CACA;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"autoDecorateContent.cjs","names":["NodeTypes"],"sources":["../../../src/utils/autoDecorateContent.ts"],"sourcesContent":["import { getMarkdownMetadata } from '@intlayer/core/markdown';\nimport {\n getInsertionValues,\n html,\n insert,\n md,\n} from '@intlayer/core/transpiler';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Check if a string is a markdown string\n */\nconst isMarkdown = (str: string): boolean => {\n // Check for common markdown indicators\n const patterns = [\n /^\\s*---/m, // Front Matter\n /^\\s*#+\\s/m, // Headers: # Title\n /^\\s*[-*+]\\s/m, // Unordered lists: - Item or * Item\n /^\\s*\\d+\\.\\s/m, // Ordered lists: 1. Item\n /^\\s*>\\s/m, // Blockquotes: > Quote\n /\\[.+\\]\\(.+\\)/, // Links: [text](url)\n /!\\[.+\\]\\(.+\\)/, // Images: ![alt](url)\n /`{1,3}.+`{1,3}/, // Code blocks or inline code: `code` or ```code```\n /\\*\\*.+\\*\\*/, // Bold: **text**\n /__.+__/, // Bold: __text__\n /<(https?:\\/\\/[^\\s>]+)>/, // Autolinks: <http://...>\n ];\n\n return patterns.some((pattern) => pattern.test(str));\n};\n\n/**\n * Check if a string is an insertion string\n */\nconst isInsertion = (str: string): boolean =>\n getInsertionValues(str).length > 0;\n\n/**\n * Check if a string is an HTML/JSX string\n * Matches:\n * - <Tag>\n * - </Tag>\n * - <Tag />\n * - <Tag attribute=\"value\">\n * - <Component.SubComponent>\n */\nconst isHTML = (str: string): boolean => {\n // 1. Matches opening or self-closing tags: <Tag ... > or <Tag ... />\n // - Must start with < followed by a letter (to avoid math comparisons like a < b)\n // - Allows alphanumeric, hyphens, and dots (for Namespaced components) in tag name\n // - Allows attributes until the closing >\n const openTagRegex = /<[a-zA-Z][a-zA-Z0-9\\-.]*(\\s+[^>]*)?\\/?>/;\n\n // 2. Matches closing tags: </Tag>\n const closeTagRegex = /<\\/[a-zA-Z][a-zA-Z0-9\\-.]*\\s*>/;\n\n return openTagRegex.test(str) || closeTagRegex.test(str);\n};\n\nconst leafNodeTypes: string[] = [\n NodeTypes.HTML,\n NodeTypes.MARKDOWN,\n NodeTypes.INSERTION,\n NodeTypes.FILE,\n NodeTypes.REACT_NODE,\n NodeTypes.TEXT,\n NodeTypes.NUMBER,\n NodeTypes.BOOLEAN,\n NodeTypes.NULL,\n NodeTypes.UNKNOWN,\n];\n\ntype AutoTransformationOptions = {\n markdown?: boolean;\n html?: boolean;\n insertion?: boolean;\n};\n\n/**\n * Automatically decorate content strings with md() or insert() if they match\n */\nexport const autoDecorateContent = (\n content: any,\n options: boolean | AutoTransformationOptions = true\n): any => {\n if (options === false) {\n return content;\n }\n\n const {\n markdown = true,\n html: htmlOption = true,\n insertion = true,\n } = typeof options === 'object' ? options : {};\n\n if (typeof content === 'string') {\n if (markdown && isMarkdown(content)) {\n const markdownNode = md(content);\n\n return {\n ...markdownNode,\n metadata: getMarkdownMetadata(content),\n };\n }\n\n if (htmlOption && isHTML(content)) {\n return html(content);\n }\n\n if (insertion && isInsertion(content)) {\n return insert(content);\n }\n\n return content;\n }\n\n if (Array.isArray(content)) {\n return content.map((item) => autoDecorateContent(item, options));\n }\n\n if (content && typeof content === 'object') {\n // If it's already a decorated node (has nodeType)\n if ('nodeType' in content) {\n const nodeType = content.nodeType;\n\n // If it's a leaf node type, don't re-decorate its content\n if (leafNodeTypes.includes(nodeType)) {\n return content;\n }\n\n // If it's a container node type (like translation, enumeration, etc.), recurse into its content field\n if (nodeType in content) {\n return {\n ...content,\n [nodeType]: autoDecorateContent(content[nodeType], options),\n };\n }\n\n return content;\n }\n\n // Plain object, recurse into all keys\n const result: Record<string, any> = {};\n for (const key of Object.keys(content)) {\n result[key] = autoDecorateContent(content[key], options);\n }\n return result;\n }\n\n return content;\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,cAAc,QAAyB;AAgB3C,QAAO;EAbL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGa,CAAC,MAAM,YAAY,QAAQ,KAAK,IAAI,CAAC;;;;;AAMtD,MAAM,eAAe,0DACA,IAAI,CAAC,SAAS;;;;;;;;;;AAWnC,MAAM,UAAU,QAAyB;AAUvC,QAAO,0CAAa,KAAK,IAAI,IAAI,iCAAc,KAAK,IAAI;;AAG1D,MAAM,gBAA0B;CAC9BA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACX;;;;AAWD,MAAa,uBACX,SACA,UAA+C,SACvC;AACR,KAAI,YAAY,MACd,QAAO;CAGT,MAAM,EACJ,WAAW,MACX,MAAM,aAAa,MACnB,YAAY,SACV,OAAO,YAAY,WAAW,UAAU,EAAE;AAE9C,KAAI,OAAO,YAAY,UAAU;AAC/B,MAAI,YAAY,WAAW,QAAQ,CAGjC,QAAO;GACL,qCAHsB,QAGP;GACf,2DAA8B,QAAQ;GACvC;AAGH,MAAI,cAAc,OAAO,QAAQ,CAC/B,4CAAY,QAAQ;AAGtB,MAAI,aAAa,YAAY,QAAQ,CACnC,8CAAc,QAAQ;AAGxB,SAAO;;AAGT,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QAAQ,KAAK,SAAS,oBAAoB,MAAM,QAAQ,CAAC;AAGlE,KAAI,WAAW,OAAO,YAAY,UAAU;AAE1C,MAAI,cAAc,SAAS;GACzB,MAAM,WAAW,QAAQ;AAGzB,OAAI,cAAc,SAAS,SAAS,CAClC,QAAO;AAIT,OAAI,YAAY,QACd,QAAO;IACL,GAAG;KACF,WAAW,oBAAoB,QAAQ,WAAW,QAAQ;IAC5D;AAGH,UAAO;;EAIT,MAAM,SAA8B,EAAE;AACtC,OAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,CACpC,QAAO,OAAO,oBAAoB,QAAQ,MAAM,QAAQ;AAE1D,SAAO;;AAGT,QAAO"}
1
+ {"version":3,"file":"autoDecorateContent.cjs","names":["NodeTypes"],"sources":["../../../src/utils/autoDecorateContent.ts"],"sourcesContent":["import { getMarkdownMetadata } from '@intlayer/core/markdown';\nimport {\n getInsertionValues,\n html,\n insert,\n md,\n} from '@intlayer/core/transpiler';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Check if a string is a markdown string\n */\nconst isMarkdown = (str: string): boolean => {\n // Check for common markdown indicators\n const patterns = [\n /^\\s*---/m, // Front Matter\n /^\\s*#+\\s/m, // Headers: # Title\n /^\\s*[-*+]\\s/m, // Unordered lists: - Item or * Item\n /^\\s*\\d+\\.\\s/m, // Ordered lists: 1. Item\n /^\\s*>\\s/m, // Blockquotes: > Quote\n /\\[.+\\]\\(.+\\)/, // Links: [text](url)\n /!\\[.+\\]\\(.+\\)/, // Images: ![alt](url)\n /`{1,3}.+`{1,3}/, // Code blocks or inline code: `code` or ```code```\n /\\*\\*.+\\*\\*/, // Bold: **text**\n /__.+__/, // Bold: __text__\n /<(https?:\\/\\/[^\\s>]+)>/, // Autolinks: <http://...>\n ];\n\n return patterns.some((pattern) => pattern.test(str));\n};\n\n/**\n * Check if a string is an insertion string\n */\nconst isInsertion = (str: string): boolean =>\n getInsertionValues(str).length > 0;\n\n/**\n * Check if a string is an HTML/JSX string\n * Matches:\n * - <Tag>\n * - </Tag>\n * - <Tag />\n * - <Tag attribute=\"value\">\n * - <Component.SubComponent>\n */\nconst isHTML = (str: string): boolean => {\n // 1. Matches opening or self-closing tags: <Tag ... > or <Tag ... />\n // - Must start with < followed by a letter (to avoid math comparisons like a < b)\n // - Allows alphanumeric, hyphens, and dots (for Namespaced components) in tag name\n // - Allows attributes until the closing >\n const openTagRegex = /<[a-zA-Z][a-zA-Z0-9\\-.]*(\\s+[^>]*)?\\/?>/;\n\n // 2. Matches closing tags: </Tag>\n const closeTagRegex = /<\\/[a-zA-Z][a-zA-Z0-9\\-.]*\\s*>/;\n\n return openTagRegex.test(str) || closeTagRegex.test(str);\n};\n\nconst leafNodeTypes: string[] = [\n NodeTypes.HTML,\n NodeTypes.MARKDOWN,\n NodeTypes.INSERTION,\n NodeTypes.FILE,\n NodeTypes.REACT_NODE,\n NodeTypes.TEXT,\n NodeTypes.NUMBER,\n NodeTypes.BOOLEAN,\n NodeTypes.NULL,\n NodeTypes.UNKNOWN,\n];\n\ntype AutoTransformationOptions = {\n markdown?: boolean;\n html?: boolean;\n insertion?: boolean;\n};\n\n/**\n * Automatically decorate content strings with md() or insert() if they match\n */\nexport const autoDecorateContent = (\n content: any,\n options: boolean | AutoTransformationOptions = true\n): any => {\n if (options === false) {\n return content;\n }\n\n const {\n markdown = true,\n html: htmlOption = true,\n insertion = true,\n } = typeof options === 'object' ? options : {};\n\n if (typeof content === 'string') {\n if (markdown && isMarkdown(content)) {\n const markdownNode = md(content);\n\n return {\n ...markdownNode,\n metadata: getMarkdownMetadata(content),\n };\n }\n\n if (htmlOption && isHTML(content)) {\n return html(content);\n }\n\n if (insertion && isInsertion(content)) {\n return insert(content);\n }\n\n return content;\n }\n\n if (Array.isArray(content)) {\n return content.map((item) => autoDecorateContent(item, options));\n }\n\n if (content && typeof content === 'object') {\n // If it's already a decorated node (has nodeType)\n if ('nodeType' in content) {\n const nodeType = content.nodeType;\n\n // If it's a leaf node type, don't re-decorate its content\n if (leafNodeTypes.includes(nodeType)) {\n return content;\n }\n\n // If it's a container node type (like translation, enumeration, etc.), recurse into its content field\n if (nodeType in content) {\n return {\n ...content,\n [nodeType]: autoDecorateContent(content[nodeType], options),\n };\n }\n\n return content;\n }\n\n // Plain object, recurse into all keys\n const result: Record<string, any> = {};\n for (const key of Object.keys(content)) {\n result[key] = autoDecorateContent(content[key], options);\n }\n return result;\n }\n\n return content;\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,cAAc,QAAyB;CAgB3C,OAAO;EAbL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAGY,CAAC,CAAC,MAAM,YAAY,QAAQ,KAAK,GAAG,CAAC;AACrD;;;;AAKA,MAAM,eAAe,0DACA,GAAG,CAAC,CAAC,SAAS;;;;;;;;;;AAWnC,MAAM,UAAU,QAAyB;CAUvC,OAAO,0CAAa,KAAK,GAAG,KAAK,iCAAc,KAAK,GAAG;AACzD;AAEA,MAAM,gBAA0B;CAC9BA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;CACVA,yBAAU;AACZ;;;;AAWA,MAAa,uBACX,SACA,UAA+C,SACvC;CACR,IAAI,YAAY,OACd,OAAO;CAGT,MAAM,EACJ,WAAW,MACX,MAAM,aAAa,MACnB,YAAY,SACV,OAAO,YAAY,WAAW,UAAU,CAAC;CAE7C,IAAI,OAAO,YAAY,UAAU;EAC/B,IAAI,YAAY,WAAW,OAAO,GAGhC,OAAO;GACL,qCAHsB,OAGR;GACd,2DAA8B,OAAO;EACvC;EAGF,IAAI,cAAc,OAAO,OAAO,GAC9B,2CAAY,OAAO;EAGrB,IAAI,aAAa,YAAY,OAAO,GAClC,6CAAc,OAAO;EAGvB,OAAO;CACT;CAEA,IAAI,MAAM,QAAQ,OAAO,GACvB,OAAO,QAAQ,KAAK,SAAS,oBAAoB,MAAM,OAAO,CAAC;CAGjE,IAAI,WAAW,OAAO,YAAY,UAAU;EAE1C,IAAI,cAAc,SAAS;GACzB,MAAM,WAAW,QAAQ;GAGzB,IAAI,cAAc,SAAS,QAAQ,GACjC,OAAO;GAIT,IAAI,YAAY,SACd,OAAO;IACL,GAAG;KACF,WAAW,oBAAoB,QAAQ,WAAW,OAAO;GAC5D;GAGF,OAAO;EACT;EAGA,MAAM,SAA8B,CAAC;EACrC,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,GACnC,OAAO,OAAO,oBAAoB,QAAQ,MAAM,OAAO;EAEzD,OAAO;CACT;CAEA,OAAO;AACT"}
@@ -64,7 +64,7 @@ const buildComponentFilesList = (config, excludePattern) => {
64
64
  const contentDeclarationPattern = config.content.fileExtensions.map((ext) => `/**/*${ext}`);
65
65
  const patterns = [...traversePattern, ...normalizeToArray(compilerTransformPattern)].filter((pattern) => typeof pattern === "string").filter((pattern) => !pattern.startsWith("!")).map(_intlayer_config_utils.normalizePath);
66
66
  const userExcludes = traversePattern.filter((pattern) => typeof pattern === "string" && pattern.startsWith("!")).map((pattern) => pattern.slice(1));
67
- const baseExcludePatterns = Array.from(new Set([
67
+ const baseExcludePatterns = Array.from(/* @__PURE__ */ new Set([
68
68
  ...DEFAULT_EXCLUDE_PATTERNS,
69
69
  ...userExcludes,
70
70
  ...excludePattern ?? [],
@@ -86,7 +86,7 @@ const buildComponentFilesList = (config, excludePattern) => {
86
86
  absolute: true,
87
87
  dot: false
88
88
  }));
89
- return Array.from(new Set([...normalFiles, ...nodeModulesFiles]));
89
+ return Array.from(/* @__PURE__ */ new Set([...normalFiles, ...nodeModulesFiles]));
90
90
  };
91
91
 
92
92
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"buildComponentFilesList.cjs","names":["sep","TRAVERSE_PATTERN","normalizePath","fg"],"sources":["../../../src/utils/buildComponentFilesList.ts"],"sourcesContent":["import { isAbsolute, relative, resolve, sep } from 'node:path';\nimport { TRAVERSE_PATTERN } from '@intlayer/config/defaultValues';\nimport { normalizePath } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport fg from 'fast-glob';\n\n/**\n * Normalizes a pattern value to an array\n */\nconst normalizeToArray = <T>(value: T | T[]): T[] =>\n Array.isArray(value) ? value : [value];\n\n/**\n * Remove directories that are subdirectories of others in the list so files\n * are never scanned twice.\n * Example: ['/root', '/root/src'] → ['/root']\n */\nconst getDistinctRootDirs = (dirs: string[]): string[] => {\n const uniqueDirs = Array.from(new Set(dirs.map((dir) => resolve(dir))));\n uniqueDirs.sort((a, b) => a.length - b.length);\n\n return uniqueDirs.reduce((acc: string[], dir) => {\n const isNested = acc.some((parent) => {\n const rel = relative(parent, dir);\n\n return !rel.startsWith('..') && !isAbsolute(rel) && rel !== '';\n });\n if (!isNested) acc.push(dir);\n\n return acc;\n }, []);\n};\n\n/**\n * Returns true when the resolved path passes through a `node_modules` segment.\n * Works on both POSIX and Windows paths.\n */\nconst isInsideNodeModules = (dir: string): boolean =>\n resolve(dir).split(sep).includes('node_modules');\n\n/**\n * Default exclude patterns derived from TRAVERSE_PATTERN.\n * Extracted once so the function body can reference them without re-computing.\n */\nconst DEFAULT_EXCLUDE_PATTERNS: string[] = TRAVERSE_PATTERN.filter(\n (p): p is string => typeof p === 'string' && p.startsWith('!')\n).map((p) => p.slice(1));\n\n/**\n * Builds a deduplicated list of absolute file paths matching the given patterns.\n *\n * Handles multiple root directories (deduplicates overlapping roots), exclude\n * patterns, negation patterns embedded in `traversePattern`, and optional\n * dot-file inclusion.\n *\n * Special case: `codeDir` entries that live inside `node_modules` (e.g. a\n * design-system package installed as a workspace dependency) are scanned as\n * their own explicit roots. They are NOT collapsed into the project root so\n * the `*\\/node_modules\\/**` exclusion does not silently drop them.\n *\n * @example\n * // Single root with excludes\n * const files = buildComponentFilesList(config);\n *\n * @example\n * // Design-system package inside node_modules is still scanned\n * // intlayer.config.ts: { content: { codeDir: ['node_modules/my-ds/src'] } }\n * const files = buildComponentFilesList(config);\n */\nexport const buildComponentFilesList = (\n config: IntlayerConfig,\n excludePattern?: string[]\n): string[] => {\n const traversePattern = config.build.traversePattern;\n const compilerTransformPattern = config.compiler.transformPattern;\n const contentDeclarationPattern = config.content.fileExtensions.map(\n (ext) => `/**/*${ext}`\n );\n\n const patterns = [\n ...traversePattern,\n ...normalizeToArray(compilerTransformPattern),\n ]\n .filter((pattern) => typeof pattern === 'string')\n .filter((pattern) => !pattern.startsWith('!'))\n .map(normalizePath);\n\n // User-supplied negations from traversePattern\n const userExcludes = traversePattern\n .filter(\n (pattern): pattern is string =>\n typeof pattern === 'string' && pattern.startsWith('!')\n )\n .map((pattern) => pattern.slice(1));\n\n // Full exclude list: defaults (from TRAVERSE_PATTERN) + user overrides + caller extras + content files.\n // DEFAULT_EXCLUDE_PATTERNS acts as a safety floor — if the user provides a\n // partial traversePattern that omits some defaults, they are still applied.\n const baseExcludePatterns = Array.from(\n new Set([\n ...DEFAULT_EXCLUDE_PATTERNS,\n ...userExcludes,\n ...(excludePattern ?? []),\n ...contentDeclarationPattern,\n ])\n )\n .filter((pattern): pattern is string => typeof pattern === 'string')\n .map(normalizePath);\n\n // Separate codeDir entries that live inside node_modules.\n // getDistinctRootDirs would collapse them into the project root, after which\n // the **/node_modules/** ignore would silently exclude them.\n const resolvedCodeDirs = (config.content.codeDir ?? []).map((dir) =>\n resolve(dir)\n );\n const inNodeModulesCodeDirs = resolvedCodeDirs.filter(isInsideNodeModules);\n const normalCodeDirs = resolvedCodeDirs.filter(\n (dir) => !isInsideNodeModules(dir)\n );\n\n // Normal roots: project base + regular codeDir entries, deduplicated.\n const normalRoots = getDistinctRootDirs([\n config.system.baseDir,\n ...normalCodeDirs,\n ]);\n\n const normalFiles = normalRoots.flatMap((root) =>\n fg.sync(patterns, {\n cwd: root,\n ignore: baseExcludePatterns,\n absolute: true,\n dot: true, // needed for .intlayer and similar\n })\n );\n\n // node_modules codeDir roots: scanned directly from the package root.\n // **/node_modules/** is removed from the ignore list so it doesn't block\n // the scan (it is still applied inside the package for nested node_modules).\n const nodeModulesExcludePatterns = baseExcludePatterns.filter(\n (pattern) => !pattern.includes('node_modules')\n );\n\n const nodeModulesFiles = inNodeModulesCodeDirs.flatMap((dir) =>\n fg.sync(patterns, {\n cwd: dir,\n ignore: nodeModulesExcludePatterns,\n absolute: true,\n dot: false,\n })\n );\n\n return Array.from(new Set([...normalFiles, ...nodeModulesFiles]));\n};\n"],"mappings":";;;;;;;;;;;;AASA,MAAM,oBAAuB,UAC3B,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;;;;;;AAOxC,MAAM,uBAAuB,SAA6B;CACxD,MAAM,aAAa,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,+BAAgB,IAAI,CAAC,CAAC,CAAC;AACvE,YAAW,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO;AAE9C,QAAO,WAAW,QAAQ,KAAe,QAAQ;AAM/C,MAAI,CALa,IAAI,MAAM,WAAW;GACpC,MAAM,8BAAe,QAAQ,IAAI;AAEjC,UAAO,CAAC,IAAI,WAAW,KAAK,IAAI,2BAAY,IAAI,IAAI,QAAQ;IAEjD,CAAE,KAAI,KAAK,IAAI;AAE5B,SAAO;IACN,EAAE,CAAC;;;;;;AAOR,MAAM,uBAAuB,+BACnB,IAAI,CAAC,MAAMA,cAAI,CAAC,SAAS,eAAe;;;;;AAMlD,MAAM,2BAAqCC,gDAAiB,QACzD,MAAmB,OAAO,MAAM,YAAY,EAAE,WAAW,IAAI,CAC/D,CAAC,KAAK,MAAM,EAAE,MAAM,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;AAuBxB,MAAa,2BACX,QACA,mBACa;CACb,MAAM,kBAAkB,OAAO,MAAM;CACrC,MAAM,2BAA2B,OAAO,SAAS;CACjD,MAAM,4BAA4B,OAAO,QAAQ,eAAe,KAC7D,QAAQ,QAAQ,MAClB;CAED,MAAM,WAAW,CACf,GAAG,iBACH,GAAG,iBAAiB,yBAAyB,CAC9C,CACE,QAAQ,YAAY,OAAO,YAAY,SAAS,CAChD,QAAQ,YAAY,CAAC,QAAQ,WAAW,IAAI,CAAC,CAC7C,IAAIC,qCAAc;CAGrB,MAAM,eAAe,gBAClB,QACE,YACC,OAAO,YAAY,YAAY,QAAQ,WAAW,IAAI,CACzD,CACA,KAAK,YAAY,QAAQ,MAAM,EAAE,CAAC;CAKrC,MAAM,sBAAsB,MAAM,KAChC,IAAI,IAAI;EACN,GAAG;EACH,GAAG;EACH,GAAI,kBAAkB,EAAE;EACxB,GAAG;EACJ,CAAC,CACH,CACE,QAAQ,YAA+B,OAAO,YAAY,SAAS,CACnE,IAAIA,qCAAc;CAKrB,MAAM,oBAAoB,OAAO,QAAQ,WAAW,EAAE,EAAE,KAAK,+BACnD,IAAI,CACb;CACD,MAAM,wBAAwB,iBAAiB,OAAO,oBAAoB;CAC1E,MAAM,iBAAiB,iBAAiB,QACrC,QAAQ,CAAC,oBAAoB,IAAI,CACnC;CAQD,MAAM,cALc,oBAAoB,CACtC,OAAO,OAAO,SACd,GAAG,eACJ,CAE8B,CAAC,SAAS,SACvCC,kBAAG,KAAK,UAAU;EAChB,KAAK;EACL,QAAQ;EACR,UAAU;EACV,KAAK;EACN,CAAC,CACH;CAKD,MAAM,6BAA6B,oBAAoB,QACpD,YAAY,CAAC,QAAQ,SAAS,eAAe,CAC/C;CAED,MAAM,mBAAmB,sBAAsB,SAAS,QACtDA,kBAAG,KAAK,UAAU;EAChB,KAAK;EACL,QAAQ;EACR,UAAU;EACV,KAAK;EACN,CAAC,CACH;AAED,QAAO,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,aAAa,GAAG,iBAAiB,CAAC,CAAC"}
1
+ {"version":3,"file":"buildComponentFilesList.cjs","names":["sep","TRAVERSE_PATTERN","normalizePath","fg"],"sources":["../../../src/utils/buildComponentFilesList.ts"],"sourcesContent":["import { isAbsolute, relative, resolve, sep } from 'node:path';\nimport { TRAVERSE_PATTERN } from '@intlayer/config/defaultValues';\nimport { normalizePath } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport fg from 'fast-glob';\n\n/**\n * Normalizes a pattern value to an array\n */\nconst normalizeToArray = <T>(value: T | T[]): T[] =>\n Array.isArray(value) ? value : [value];\n\n/**\n * Remove directories that are subdirectories of others in the list so files\n * are never scanned twice.\n * Example: ['/root', '/root/src'] → ['/root']\n */\nconst getDistinctRootDirs = (dirs: string[]): string[] => {\n const uniqueDirs = Array.from(new Set(dirs.map((dir) => resolve(dir))));\n uniqueDirs.sort((a, b) => a.length - b.length);\n\n return uniqueDirs.reduce((acc: string[], dir) => {\n const isNested = acc.some((parent) => {\n const rel = relative(parent, dir);\n\n return !rel.startsWith('..') && !isAbsolute(rel) && rel !== '';\n });\n if (!isNested) acc.push(dir);\n\n return acc;\n }, []);\n};\n\n/**\n * Returns true when the resolved path passes through a `node_modules` segment.\n * Works on both POSIX and Windows paths.\n */\nconst isInsideNodeModules = (dir: string): boolean =>\n resolve(dir).split(sep).includes('node_modules');\n\n/**\n * Default exclude patterns derived from TRAVERSE_PATTERN.\n * Extracted once so the function body can reference them without re-computing.\n */\nconst DEFAULT_EXCLUDE_PATTERNS: string[] = TRAVERSE_PATTERN.filter(\n (p): p is string => typeof p === 'string' && p.startsWith('!')\n).map((p) => p.slice(1));\n\n/**\n * Builds a deduplicated list of absolute file paths matching the given patterns.\n *\n * Handles multiple root directories (deduplicates overlapping roots), exclude\n * patterns, negation patterns embedded in `traversePattern`, and optional\n * dot-file inclusion.\n *\n * Special case: `codeDir` entries that live inside `node_modules` (e.g. a\n * design-system package installed as a workspace dependency) are scanned as\n * their own explicit roots. They are NOT collapsed into the project root so\n * the `*\\/node_modules\\/**` exclusion does not silently drop them.\n *\n * @example\n * // Single root with excludes\n * const files = buildComponentFilesList(config);\n *\n * @example\n * // Design-system package inside node_modules is still scanned\n * // intlayer.config.ts: { content: { codeDir: ['node_modules/my-ds/src'] } }\n * const files = buildComponentFilesList(config);\n */\nexport const buildComponentFilesList = (\n config: IntlayerConfig,\n excludePattern?: string[]\n): string[] => {\n const traversePattern = config.build.traversePattern;\n const compilerTransformPattern = config.compiler.transformPattern;\n const contentDeclarationPattern = config.content.fileExtensions.map(\n (ext) => `/**/*${ext}`\n );\n\n const patterns = [\n ...traversePattern,\n ...normalizeToArray(compilerTransformPattern),\n ]\n .filter((pattern) => typeof pattern === 'string')\n .filter((pattern) => !pattern.startsWith('!'))\n .map(normalizePath);\n\n // User-supplied negations from traversePattern\n const userExcludes = traversePattern\n .filter(\n (pattern): pattern is string =>\n typeof pattern === 'string' && pattern.startsWith('!')\n )\n .map((pattern) => pattern.slice(1));\n\n // Full exclude list: defaults (from TRAVERSE_PATTERN) + user overrides + caller extras + content files.\n // DEFAULT_EXCLUDE_PATTERNS acts as a safety floor — if the user provides a\n // partial traversePattern that omits some defaults, they are still applied.\n const baseExcludePatterns = Array.from(\n new Set([\n ...DEFAULT_EXCLUDE_PATTERNS,\n ...userExcludes,\n ...(excludePattern ?? []),\n ...contentDeclarationPattern,\n ])\n )\n .filter((pattern): pattern is string => typeof pattern === 'string')\n .map(normalizePath);\n\n // Separate codeDir entries that live inside node_modules.\n // getDistinctRootDirs would collapse them into the project root, after which\n // the **/node_modules/** ignore would silently exclude them.\n const resolvedCodeDirs = (config.content.codeDir ?? []).map((dir) =>\n resolve(dir)\n );\n const inNodeModulesCodeDirs = resolvedCodeDirs.filter(isInsideNodeModules);\n const normalCodeDirs = resolvedCodeDirs.filter(\n (dir) => !isInsideNodeModules(dir)\n );\n\n // Normal roots: project base + regular codeDir entries, deduplicated.\n const normalRoots = getDistinctRootDirs([\n config.system.baseDir,\n ...normalCodeDirs,\n ]);\n\n const normalFiles = normalRoots.flatMap((root) =>\n fg.sync(patterns, {\n cwd: root,\n ignore: baseExcludePatterns,\n absolute: true,\n dot: true, // needed for .intlayer and similar\n })\n );\n\n // node_modules codeDir roots: scanned directly from the package root.\n // **/node_modules/** is removed from the ignore list so it doesn't block\n // the scan (it is still applied inside the package for nested node_modules).\n const nodeModulesExcludePatterns = baseExcludePatterns.filter(\n (pattern) => !pattern.includes('node_modules')\n );\n\n const nodeModulesFiles = inNodeModulesCodeDirs.flatMap((dir) =>\n fg.sync(patterns, {\n cwd: dir,\n ignore: nodeModulesExcludePatterns,\n absolute: true,\n dot: false,\n })\n );\n\n return Array.from(new Set([...normalFiles, ...nodeModulesFiles]));\n};\n"],"mappings":";;;;;;;;;;;;AASA,MAAM,oBAAuB,UAC3B,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;;;;;;AAOvC,MAAM,uBAAuB,SAA6B;CACxD,MAAM,aAAa,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,+BAAgB,GAAG,CAAC,CAAC,CAAC;CACtE,WAAW,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;CAE7C,OAAO,WAAW,QAAQ,KAAe,QAAQ;EAM/C,IAAI,CALa,IAAI,MAAM,WAAW;GACpC,MAAM,8BAAe,QAAQ,GAAG;GAEhC,OAAO,CAAC,IAAI,WAAW,IAAI,KAAK,2BAAY,GAAG,KAAK,QAAQ;EAC9D,CACY,GAAG,IAAI,KAAK,GAAG;EAE3B,OAAO;CACT,GAAG,CAAC,CAAC;AACP;;;;;AAMA,MAAM,uBAAuB,+BACnB,GAAG,CAAC,CAAC,MAAMA,aAAG,CAAC,CAAC,SAAS,cAAc;;;;;AAMjD,MAAM,2BAAqCC,gDAAiB,QACzD,MAAmB,OAAO,MAAM,YAAY,EAAE,WAAW,GAAG,CAC/D,CAAC,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;AAuBvB,MAAa,2BACX,QACA,mBACa;CACb,MAAM,kBAAkB,OAAO,MAAM;CACrC,MAAM,2BAA2B,OAAO,SAAS;CACjD,MAAM,4BAA4B,OAAO,QAAQ,eAAe,KAC7D,QAAQ,QAAQ,KACnB;CAEA,MAAM,WAAW,CACf,GAAG,iBACH,GAAG,iBAAiB,wBAAwB,CAC9C,CAAC,CACE,QAAQ,YAAY,OAAO,YAAY,QAAQ,CAAC,CAChD,QAAQ,YAAY,CAAC,QAAQ,WAAW,GAAG,CAAC,CAAC,CAC7C,IAAIC,oCAAa;CAGpB,MAAM,eAAe,gBAClB,QACE,YACC,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG,CACzD,CAAC,CACA,KAAK,YAAY,QAAQ,MAAM,CAAC,CAAC;CAKpC,MAAM,sBAAsB,MAAM,qBAChC,IAAI,IAAI;EACN,GAAG;EACH,GAAG;EACH,GAAI,kBAAkB,CAAC;EACvB,GAAG;CACL,CAAC,CACH,CAAC,CACE,QAAQ,YAA+B,OAAO,YAAY,QAAQ,CAAC,CACnE,IAAIA,oCAAa;CAKpB,MAAM,oBAAoB,OAAO,QAAQ,WAAW,CAAC,EAAC,CAAE,KAAK,+BACnD,GAAG,CACb;CACA,MAAM,wBAAwB,iBAAiB,OAAO,mBAAmB;CACzE,MAAM,iBAAiB,iBAAiB,QACrC,QAAQ,CAAC,oBAAoB,GAAG,CACnC;CAQA,MAAM,cALc,oBAAoB,CACtC,OAAO,OAAO,SACd,GAAG,cACL,CAE8B,CAAC,CAAC,SAAS,SACvCC,kBAAG,KAAK,UAAU;EAChB,KAAK;EACL,QAAQ;EACR,UAAU;EACV,KAAK;CACP,CAAC,CACH;CAKA,MAAM,6BAA6B,oBAAoB,QACpD,YAAY,CAAC,QAAQ,SAAS,cAAc,CAC/C;CAEA,MAAM,mBAAmB,sBAAsB,SAAS,QACtDA,kBAAG,KAAK,UAAU;EAChB,KAAK;EACL,QAAQ;EACR,UAAU;EACV,KAAK;CACP,CAAC,CACH;CAEA,OAAO,MAAM,qBAAK,IAAI,IAAI,CAAC,GAAG,aAAa,GAAG,gBAAgB,CAAC,CAAC;AAClE"}
@@ -70,9 +70,10 @@ const buildComponentFilesList = (config) => {
70
70
  */
71
71
  const buildComponentFilesListFromConfig = (intlayerConfig) => {
72
72
  const { build: { traversePattern }, system: { baseDir }, content: { codeDir, fileExtensions }, compiler: { excludePattern } } = intlayerConfig;
73
+ const excludePatterns = [...fileExtensions.map((ext) => `**/*${ext}`), ...Array.isArray(excludePattern) ? excludePattern : [excludePattern]].filter((p) => typeof p === "string");
73
74
  return buildComponentFilesList({
74
75
  transformPattern: traversePattern,
75
- excludePattern: [...fileExtensions.map((ext) => `**/*${ext}`), ...Array.isArray(excludePattern) ? excludePattern : [excludePattern]].filter((p) => typeof p === "string"),
76
+ excludePattern: excludePatterns,
76
77
  baseDir: [baseDir, ...codeDir],
77
78
  dot: true
78
79
  });
@@ -1 +1 @@
1
- {"version":3,"file":"buildFilesList.cjs","names":["normalize","fg"],"sources":["../../../src/utils/buildFilesList.ts"],"sourcesContent":["import { isAbsolute, normalize, relative, resolve } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport fg from 'fast-glob';\n\n/**\n * Options for building the files list\n */\nexport type BuildComponentFilesListOptions = {\n /**\n * Glob patterns to match files\n */\n transformPattern: string | string[];\n /**\n * Glob patterns to exclude files\n */\n excludePattern?: string | string[];\n /**\n * Base directory (or directories) for file resolution.\n * When multiple directories are provided, subdirectories of others are\n * automatically deduplicated so files are never scanned twice.\n */\n baseDir: string | string[];\n /**\n * Whether to include dot-prefixed files and directories (default: false)\n */\n dot?: boolean;\n};\n\n/**\n * Normalizes a pattern value to an array\n */\nconst normalizeToArray = <T>(value: T | T[]): T[] =>\n Array.isArray(value) ? value : [value];\n\n/**\n * Remove directories that are subdirectories of others in the list so files\n * are never scanned twice.\n * Example: ['/root', '/root/src'] → ['/root']\n */\nconst getDistinctRootDirs = (dirs: string[]): string[] => {\n const uniqueDirs = Array.from(new Set(dirs.map((dir) => resolve(dir))));\n uniqueDirs.sort((a, b) => a.length - b.length);\n\n return uniqueDirs.reduce((acc: string[], dir) => {\n const isNested = acc.some((parent) => {\n const rel = relative(parent, dir);\n return !rel.startsWith('..') && !isAbsolute(rel) && rel !== '';\n });\n if (!isNested) acc.push(dir);\n return acc;\n }, []);\n};\n\n/**\n * Builds a deduplicated list of absolute file paths matching the given patterns.\n *\n * Handles multiple root directories (deduplicates overlapping roots), exclude\n * patterns, negation patterns embedded in `transformPattern`, and optional\n * dot-file inclusion.\n *\n * @example\n * // Single root with excludes\n * const files = buildComponentFilesList({\n * transformPattern: 'src/**\\/*.{ts,tsx}',\n * excludePattern: ['**\\/node_modules\\/**'],\n * baseDir: '/path/to/project',\n * });\n *\n * @example\n * // Multiple roots (e.g. baseDir + codeDir), dot files included\n * const files = buildComponentFilesList({\n * transformPattern: config.build.traversePattern,\n * baseDir: [config.system.baseDir, ...config.content.codeDir],\n * dot: true,\n * });\n */\nexport const buildComponentFilesList = (\n config: BuildComponentFilesListOptions\n): string[] => {\n const {\n transformPattern,\n excludePattern = [],\n baseDir,\n dot = false,\n } = config;\n\n const patterns = normalizeToArray(transformPattern)\n .filter(\n (pattern): pattern is string =>\n typeof pattern === 'string' && !pattern.startsWith('!')\n )\n .map(normalize); // Ensure it works with Windows\n\n const excludePatterns = [\n ...normalizeToArray(excludePattern),\n // Treat negation entries in transformPattern as additional excludes\n ...normalizeToArray(transformPattern)\n .filter(\n (pattern): pattern is string =>\n typeof pattern === 'string' && pattern.startsWith('!')\n )\n .map((pattern) => pattern.slice(1)),\n ]\n .filter((pattern): pattern is string => typeof pattern === 'string')\n .map(normalize); // Ensure it works with Windows\n\n const roots = getDistinctRootDirs(normalizeToArray(baseDir));\n\n return Array.from(\n new Set(\n roots.flatMap((root) =>\n fg.sync(patterns, {\n cwd: root,\n ignore: excludePatterns,\n absolute: true,\n dot,\n })\n )\n )\n );\n};\n\n/**\n * Convenience wrapper that derives all file-list options directly from an\n * `IntlayerConfig` object.\n *\n * Scans `[baseDir, ...codeDir]` using `build.traversePattern`, excludes\n * content declaration file extensions and any `compiler.excludePattern`\n * entries defined in the configuration, and includes dot files.\n */\nexport const buildComponentFilesListFromConfig = (\n intlayerConfig: IntlayerConfig\n): string[] => {\n const {\n build: { traversePattern },\n system: { baseDir },\n content: { codeDir, fileExtensions },\n compiler: { excludePattern },\n } = intlayerConfig;\n\n const excludePatterns = [\n // Exclude content declaration files (e.g. **/*.content.ts)\n ...fileExtensions.map((ext) => `**/*${ext}`),\n ...(Array.isArray(excludePattern) ? excludePattern : [excludePattern]),\n ].filter((p): p is string => typeof p === 'string');\n\n return buildComponentFilesList({\n transformPattern: traversePattern,\n excludePattern: excludePatterns,\n baseDir: [baseDir, ...codeDir],\n dot: true,\n });\n};\n"],"mappings":";;;;;;;;;;AA+BA,MAAM,oBAAuB,UAC3B,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;;;;;;AAOxC,MAAM,uBAAuB,SAA6B;CACxD,MAAM,aAAa,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,+BAAgB,IAAI,CAAC,CAAC,CAAC;AACvE,YAAW,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO;AAE9C,QAAO,WAAW,QAAQ,KAAe,QAAQ;AAK/C,MAAI,CAJa,IAAI,MAAM,WAAW;GACpC,MAAM,8BAAe,QAAQ,IAAI;AACjC,UAAO,CAAC,IAAI,WAAW,KAAK,IAAI,2BAAY,IAAI,IAAI,QAAQ;IAEjD,CAAE,KAAI,KAAK,IAAI;AAC5B,SAAO;IACN,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BR,MAAa,2BACX,WACa;CACb,MAAM,EACJ,kBACA,iBAAiB,EAAE,EACnB,SACA,MAAM,UACJ;CAEJ,MAAM,WAAW,iBAAiB,iBAAiB,CAChD,QACE,YACC,OAAO,YAAY,YAAY,CAAC,QAAQ,WAAW,IAAI,CAC1D,CACA,IAAIA,oBAAU;CAEjB,MAAM,kBAAkB,CACtB,GAAG,iBAAiB,eAAe,EAEnC,GAAG,iBAAiB,iBAAiB,CAClC,QACE,YACC,OAAO,YAAY,YAAY,QAAQ,WAAW,IAAI,CACzD,CACA,KAAK,YAAY,QAAQ,MAAM,EAAE,CAAC,CACtC,CACE,QAAQ,YAA+B,OAAO,YAAY,SAAS,CACnE,IAAIA,oBAAU;CAEjB,MAAM,QAAQ,oBAAoB,iBAAiB,QAAQ,CAAC;AAE5D,QAAO,MAAM,KACX,IAAI,IACF,MAAM,SAAS,SACbC,kBAAG,KAAK,UAAU;EAChB,KAAK;EACL,QAAQ;EACR,UAAU;EACV;EACD,CAAC,CACH,CACF,CACF;;;;;;;;;;AAWH,MAAa,qCACX,mBACa;CACb,MAAM,EACJ,OAAO,EAAE,mBACT,QAAQ,EAAE,WACV,SAAS,EAAE,SAAS,kBACpB,UAAU,EAAE,qBACV;AAQJ,QAAO,wBAAwB;EAC7B,kBAAkB;EAClB,gBARsB,CAEtB,GAAG,eAAe,KAAK,QAAQ,OAAO,MAAM,EAC5C,GAAI,MAAM,QAAQ,eAAe,GAAG,iBAAiB,CAAC,eAAe,CACtE,CAAC,QAAQ,MAAmB,OAAO,MAAM,SAIT;EAC/B,SAAS,CAAC,SAAS,GAAG,QAAQ;EAC9B,KAAK;EACN,CAAC"}
1
+ {"version":3,"file":"buildFilesList.cjs","names":["normalize","fg"],"sources":["../../../src/utils/buildFilesList.ts"],"sourcesContent":["import { isAbsolute, normalize, relative, resolve } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport fg from 'fast-glob';\n\n/**\n * Options for building the files list\n */\nexport type BuildComponentFilesListOptions = {\n /**\n * Glob patterns to match files\n */\n transformPattern: string | string[];\n /**\n * Glob patterns to exclude files\n */\n excludePattern?: string | string[];\n /**\n * Base directory (or directories) for file resolution.\n * When multiple directories are provided, subdirectories of others are\n * automatically deduplicated so files are never scanned twice.\n */\n baseDir: string | string[];\n /**\n * Whether to include dot-prefixed files and directories (default: false)\n */\n dot?: boolean;\n};\n\n/**\n * Normalizes a pattern value to an array\n */\nconst normalizeToArray = <T>(value: T | T[]): T[] =>\n Array.isArray(value) ? value : [value];\n\n/**\n * Remove directories that are subdirectories of others in the list so files\n * are never scanned twice.\n * Example: ['/root', '/root/src'] → ['/root']\n */\nconst getDistinctRootDirs = (dirs: string[]): string[] => {\n const uniqueDirs = Array.from(new Set(dirs.map((dir) => resolve(dir))));\n uniqueDirs.sort((a, b) => a.length - b.length);\n\n return uniqueDirs.reduce((acc: string[], dir) => {\n const isNested = acc.some((parent) => {\n const rel = relative(parent, dir);\n return !rel.startsWith('..') && !isAbsolute(rel) && rel !== '';\n });\n if (!isNested) acc.push(dir);\n return acc;\n }, []);\n};\n\n/**\n * Builds a deduplicated list of absolute file paths matching the given patterns.\n *\n * Handles multiple root directories (deduplicates overlapping roots), exclude\n * patterns, negation patterns embedded in `transformPattern`, and optional\n * dot-file inclusion.\n *\n * @example\n * // Single root with excludes\n * const files = buildComponentFilesList({\n * transformPattern: 'src/**\\/*.{ts,tsx}',\n * excludePattern: ['**\\/node_modules\\/**'],\n * baseDir: '/path/to/project',\n * });\n *\n * @example\n * // Multiple roots (e.g. baseDir + codeDir), dot files included\n * const files = buildComponentFilesList({\n * transformPattern: config.build.traversePattern,\n * baseDir: [config.system.baseDir, ...config.content.codeDir],\n * dot: true,\n * });\n */\nexport const buildComponentFilesList = (\n config: BuildComponentFilesListOptions\n): string[] => {\n const {\n transformPattern,\n excludePattern = [],\n baseDir,\n dot = false,\n } = config;\n\n const patterns = normalizeToArray(transformPattern)\n .filter(\n (pattern): pattern is string =>\n typeof pattern === 'string' && !pattern.startsWith('!')\n )\n .map(normalize); // Ensure it works with Windows\n\n const excludePatterns = [\n ...normalizeToArray(excludePattern),\n // Treat negation entries in transformPattern as additional excludes\n ...normalizeToArray(transformPattern)\n .filter(\n (pattern): pattern is string =>\n typeof pattern === 'string' && pattern.startsWith('!')\n )\n .map((pattern) => pattern.slice(1)),\n ]\n .filter((pattern): pattern is string => typeof pattern === 'string')\n .map(normalize); // Ensure it works with Windows\n\n const roots = getDistinctRootDirs(normalizeToArray(baseDir));\n\n return Array.from(\n new Set(\n roots.flatMap((root) =>\n fg.sync(patterns, {\n cwd: root,\n ignore: excludePatterns,\n absolute: true,\n dot,\n })\n )\n )\n );\n};\n\n/**\n * Convenience wrapper that derives all file-list options directly from an\n * `IntlayerConfig` object.\n *\n * Scans `[baseDir, ...codeDir]` using `build.traversePattern`, excludes\n * content declaration file extensions and any `compiler.excludePattern`\n * entries defined in the configuration, and includes dot files.\n */\nexport const buildComponentFilesListFromConfig = (\n intlayerConfig: IntlayerConfig\n): string[] => {\n const {\n build: { traversePattern },\n system: { baseDir },\n content: { codeDir, fileExtensions },\n compiler: { excludePattern },\n } = intlayerConfig;\n\n const excludePatterns = [\n // Exclude content declaration files (e.g. **/*.content.ts)\n ...fileExtensions.map((ext) => `**/*${ext}`),\n ...(Array.isArray(excludePattern) ? excludePattern : [excludePattern]),\n ].filter((p): p is string => typeof p === 'string');\n\n return buildComponentFilesList({\n transformPattern: traversePattern,\n excludePattern: excludePatterns,\n baseDir: [baseDir, ...codeDir],\n dot: true,\n });\n};\n"],"mappings":";;;;;;;;;;AA+BA,MAAM,oBAAuB,UAC3B,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;;;;;;AAOvC,MAAM,uBAAuB,SAA6B;CACxD,MAAM,aAAa,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,+BAAgB,GAAG,CAAC,CAAC,CAAC;CACtE,WAAW,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;CAE7C,OAAO,WAAW,QAAQ,KAAe,QAAQ;EAK/C,IAAI,CAJa,IAAI,MAAM,WAAW;GACpC,MAAM,8BAAe,QAAQ,GAAG;GAChC,OAAO,CAAC,IAAI,WAAW,IAAI,KAAK,2BAAY,GAAG,KAAK,QAAQ;EAC9D,CACY,GAAG,IAAI,KAAK,GAAG;EAC3B,OAAO;CACT,GAAG,CAAC,CAAC;AACP;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,2BACX,WACa;CACb,MAAM,EACJ,kBACA,iBAAiB,CAAC,GAClB,SACA,MAAM,UACJ;CAEJ,MAAM,WAAW,iBAAiB,gBAAgB,CAAC,CAChD,QACE,YACC,OAAO,YAAY,YAAY,CAAC,QAAQ,WAAW,GAAG,CAC1D,CAAC,CACA,IAAIA,mBAAS;CAEhB,MAAM,kBAAkB,CACtB,GAAG,iBAAiB,cAAc,GAElC,GAAG,iBAAiB,gBAAgB,CAAC,CAClC,QACE,YACC,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG,CACzD,CAAC,CACA,KAAK,YAAY,QAAQ,MAAM,CAAC,CAAC,CACtC,CAAC,CACE,QAAQ,YAA+B,OAAO,YAAY,QAAQ,CAAC,CACnE,IAAIA,mBAAS;CAEhB,MAAM,QAAQ,oBAAoB,iBAAiB,OAAO,CAAC;CAE3D,OAAO,MAAM,KACX,IAAI,IACF,MAAM,SAAS,SACbC,kBAAG,KAAK,UAAU;EAChB,KAAK;EACL,QAAQ;EACR,UAAU;EACV;CACF,CAAC,CACH,CACF,CACF;AACF;;;;;;;;;AAUA,MAAa,qCACX,mBACa;CACb,MAAM,EACJ,OAAO,EAAE,mBACT,QAAQ,EAAE,WACV,SAAS,EAAE,SAAS,kBACpB,UAAU,EAAE,qBACV;CAEJ,MAAM,kBAAkB,CAEtB,GAAG,eAAe,KAAK,QAAQ,OAAO,KAAK,GAC3C,GAAI,MAAM,QAAQ,cAAc,IAAI,iBAAiB,CAAC,cAAc,CACtE,CAAC,CAAC,QAAQ,MAAmB,OAAO,MAAM,QAAQ;CAElD,OAAO,wBAAwB;EAC7B,kBAAkB;EAClB,gBAAgB;EAChB,SAAS,CAAC,SAAS,GAAG,OAAO;EAC7B,KAAK;CACP,CAAC;AACH"}
@@ -289,7 +289,8 @@ const assembleJSON = (chunks) => {
289
289
  for (const { path, total, received } of stringParts.values()) {
290
290
  if (received.length !== total) throw new Error("Missing string parts for a path; incomplete chunk set.");
291
291
  received.sort((a, b) => a.index - b.index);
292
- setAtPath(root, path, received.map((part) => part.value).join(""));
292
+ const fullString = received.map((part) => part.value).join("");
293
+ setAtPath(root, path, fullString);
293
294
  }
294
295
  const reconcileSplitNodes = (node) => {
295
296
  if (node === null || typeof node !== "object") return node;