@intlayer/engine 9.3.0 → 9.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/README.md +24 -24
  2. package/dist/assets/initConfig/templates/cjs.txt +1 -1
  3. package/dist/assets/initConfig/templates/mjs.txt +1 -1
  4. package/dist/assets/initConfig/templates/ts.txt +1 -1
  5. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  6. package/dist/cjs/_virtual/_utils_asset.cjs +2 -1
  7. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  8. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +2 -1
  9. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
  10. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
  11. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -1
  12. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
  13. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -1
  14. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +4 -2
  15. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
  16. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
  17. package/dist/cjs/cleanOutputDir.cjs.map +1 -1
  18. package/dist/cjs/cleanRemovedContentDeclaration.cjs +7 -4
  19. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  20. package/dist/cjs/cli.cjs +2 -0
  21. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +5 -3
  22. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
  23. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
  24. package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
  25. package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
  26. package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
  27. package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
  28. package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
  29. package/dist/cjs/createType/createModuleAugmentation.cjs +2 -1
  30. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  31. package/dist/cjs/createType/createType.cjs.map +1 -1
  32. package/dist/cjs/detectFormatCommand.cjs.map +1 -1
  33. package/dist/cjs/docReview/alignBlocks.cjs +1 -1
  34. package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
  35. package/dist/cjs/docReview/computeSimilarity.cjs +0 -1
  36. package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
  37. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +0 -1
  38. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
  39. package/dist/cjs/docReview/normalizeBlock.cjs +0 -1
  40. package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
  41. package/dist/cjs/docReview/planActions.cjs +0 -1
  42. package/dist/cjs/docReview/planActions.cjs.map +1 -1
  43. package/dist/cjs/docReview/rebuildDocument.cjs +0 -1
  44. package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
  45. package/dist/cjs/docReview/reviewReport.cjs +2 -1
  46. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  47. package/dist/cjs/docReview/segmentDocument.cjs +0 -1
  48. package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
  49. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  50. package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
  51. package/dist/cjs/formatDictionary.cjs.map +1 -1
  52. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
  53. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +4 -2
  54. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
  55. package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -2
  56. package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
  57. package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
  58. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +4 -2
  59. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
  60. package/dist/cjs/init/cms.cjs.map +1 -1
  61. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
  62. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +1 -3
  63. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  64. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +2 -1
  65. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
  66. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +0 -1
  67. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
  68. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
  69. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +3 -5
  70. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  71. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -1
  72. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
  73. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +18 -12
  74. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
  75. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +57 -14
  76. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  77. package/dist/cjs/init/index.cjs +124 -45
  78. package/dist/cjs/init/index.cjs.map +1 -1
  79. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  80. package/dist/cjs/init/utils/fileSystem.cjs +3 -1
  81. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  82. package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
  83. package/dist/cjs/init/utils/index.cjs +3 -0
  84. package/dist/cjs/init/utils/jsonParser.cjs +0 -1
  85. package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
  86. package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
  87. package/dist/cjs/init/utils/packageManager.cjs +105 -7
  88. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  89. package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
  90. package/dist/cjs/init/utils/version.cjs +0 -1
  91. package/dist/cjs/init/utils/version.cjs.map +1 -1
  92. package/dist/cjs/initConfig/index.cjs +12 -8
  93. package/dist/cjs/initConfig/index.cjs.map +1 -1
  94. package/dist/cjs/installSkills/index.cjs.map +1 -1
  95. package/dist/cjs/listDictionariesPath.cjs +6 -5
  96. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  97. package/dist/cjs/listGitFiles.cjs.map +1 -1
  98. package/dist/cjs/listProjects.cjs +2 -1
  99. package/dist/cjs/listProjects.cjs.map +1 -1
  100. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +2 -1
  101. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
  102. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +8 -5
  103. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  104. package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
  105. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
  106. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
  107. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  108. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +2 -1
  109. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
  110. package/dist/cjs/loadDictionaries/log.cjs +10 -6
  111. package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
  112. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  113. package/dist/cjs/logConfigDetails.cjs +4 -3
  114. package/dist/cjs/logConfigDetails.cjs.map +1 -1
  115. package/dist/cjs/prepareIntlayer.cjs +5 -3
  116. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  117. package/dist/cjs/reduceDictionaryContent/applyMask.cjs +0 -1
  118. package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
  119. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +2 -1
  120. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
  121. package/dist/cjs/scan/calculateScore.cjs +0 -1
  122. package/dist/cjs/scan/calculateScore.cjs.map +1 -1
  123. package/dist/cjs/scan/checks.cjs +1 -1
  124. package/dist/cjs/scan/checks.cjs.map +1 -1
  125. package/dist/cjs/scan/parseHtml.cjs +0 -1
  126. package/dist/cjs/scan/parseHtml.cjs.map +1 -1
  127. package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
  128. package/dist/cjs/syncPluginKit/createFileAdapter.cjs +2 -1
  129. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
  130. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +4 -1
  131. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
  132. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +0 -1
  133. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
  134. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +0 -1
  135. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
  136. package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
  137. package/dist/cjs/utils/babelParser.cjs.map +1 -1
  138. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  139. package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
  140. package/dist/cjs/utils/chunkArray.cjs +0 -1
  141. package/dist/cjs/utils/chunkArray.cjs.map +1 -1
  142. package/dist/cjs/utils/formatter.cjs.map +1 -1
  143. package/dist/cjs/utils/getContentExtension.cjs +1 -4
  144. package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
  145. package/dist/cjs/utils/getFormatFromExtension.cjs +0 -1
  146. package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
  147. package/dist/cjs/utils/getPathHash.cjs +0 -1
  148. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  149. package/dist/cjs/utils/mergeChunks.cjs +0 -1
  150. package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
  151. package/dist/cjs/utils/pLimit.cjs +0 -1
  152. package/dist/cjs/utils/pLimit.cjs.map +1 -1
  153. package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
  154. package/dist/cjs/utils/reduceObjectFormat.cjs +0 -1
  155. package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
  156. package/dist/cjs/utils/resolveObjectPromises.cjs +0 -1
  157. package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
  158. package/dist/cjs/utils/resolveRelativePath.cjs +4 -1
  159. package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
  160. package/dist/cjs/utils/runOnce.cjs +2 -2
  161. package/dist/cjs/utils/runOnce.cjs.map +1 -1
  162. package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
  163. package/dist/cjs/utils/runParallel/bootstrap.cjs +0 -1
  164. package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
  165. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  166. package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
  167. package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
  168. package/dist/cjs/utils/sortAlphabetically.cjs +0 -1
  169. package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
  170. package/dist/cjs/utils/splitTextByLine.cjs +0 -1
  171. package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
  172. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs +0 -1
  173. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
  174. package/dist/cjs/watcher.cjs +4 -2
  175. package/dist/cjs/watcher.cjs.map +1 -1
  176. package/dist/cjs/writeConfiguration/index.cjs +2 -1
  177. package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
  178. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +0 -1
  179. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
  180. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
  181. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +26 -23
  182. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
  183. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs +6 -5
  184. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
  185. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +9 -3
  186. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  187. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +2 -1
  188. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
  189. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -1
  190. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  191. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +4 -2
  192. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  193. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  194. package/dist/esm/_virtual/_utils_asset.mjs +2 -1
  195. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +2 -1
  196. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
  197. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
  198. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
  199. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +4 -2
  200. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
  201. package/dist/esm/cleanRemovedContentDeclaration.mjs +7 -4
  202. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  203. package/dist/esm/cli.mjs +2 -2
  204. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs +5 -3
  205. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
  206. package/dist/esm/createType/createModuleAugmentation.mjs +2 -1
  207. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  208. package/dist/esm/docReview/alignBlocks.mjs +1 -1
  209. package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
  210. package/dist/esm/docReview/reviewReport.mjs +2 -1
  211. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  212. package/dist/esm/handleAdditionalContentDeclarationFile.mjs +4 -2
  213. package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
  214. package/dist/esm/handleContentDeclarationFileChange.mjs +6 -2
  215. package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
  216. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +4 -2
  217. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
  218. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +1 -3
  219. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  220. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +2 -1
  221. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
  222. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +4 -6
  223. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  224. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -1
  225. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
  226. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +17 -10
  227. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
  228. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +58 -15
  229. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  230. package/dist/esm/init/index.mjs +125 -46
  231. package/dist/esm/init/index.mjs.map +1 -1
  232. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  233. package/dist/esm/init/utils/fileSystem.mjs +3 -1
  234. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  235. package/dist/esm/init/utils/index.mjs +2 -2
  236. package/dist/esm/init/utils/packageManager.mjs +103 -8
  237. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  238. package/dist/esm/initConfig/index.mjs +12 -8
  239. package/dist/esm/initConfig/index.mjs.map +1 -1
  240. package/dist/esm/listDictionariesPath.mjs +6 -5
  241. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  242. package/dist/esm/listProjects.mjs +2 -1
  243. package/dist/esm/listProjects.mjs.map +1 -1
  244. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs +2 -1
  245. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
  246. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +8 -5
  247. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  248. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs +2 -1
  249. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
  250. package/dist/esm/loadDictionaries/log.mjs +10 -6
  251. package/dist/esm/loadDictionaries/log.mjs.map +1 -1
  252. package/dist/esm/logConfigDetails.mjs +4 -3
  253. package/dist/esm/logConfigDetails.mjs.map +1 -1
  254. package/dist/esm/prepareIntlayer.mjs +5 -3
  255. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  256. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs +2 -1
  257. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
  258. package/dist/esm/scan/checks.mjs +1 -1
  259. package/dist/esm/scan/checks.mjs.map +1 -1
  260. package/dist/esm/syncPluginKit/createFileAdapter.mjs +2 -1
  261. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
  262. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +4 -1
  263. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
  264. package/dist/esm/utils/babelParser.mjs.map +1 -1
  265. package/dist/esm/utils/getContentExtension.mjs +1 -3
  266. package/dist/esm/utils/getContentExtension.mjs.map +1 -1
  267. package/dist/esm/utils/resolveRelativePath.mjs +4 -1
  268. package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
  269. package/dist/esm/utils/runOnce.mjs +2 -2
  270. package/dist/esm/utils/runOnce.mjs.map +1 -1
  271. package/dist/esm/watcher.mjs +4 -2
  272. package/dist/esm/watcher.mjs.map +1 -1
  273. package/dist/esm/writeConfiguration/index.mjs +2 -1
  274. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  275. package/dist/esm/writeContentDeclaration/transformJSFile.mjs +26 -23
  276. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  277. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs +6 -5
  278. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
  279. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +9 -3
  280. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  281. package/dist/esm/writeContentDeclaration/writeJSFile.mjs +2 -1
  282. package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
  283. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -1
  284. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  285. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +4 -2
  286. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  287. package/dist/types/cli.d.ts +2 -2
  288. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +9 -4
  289. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  290. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +6 -2
  291. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  292. package/dist/types/init/index.d.ts +2 -7
  293. package/dist/types/init/index.d.ts.map +1 -1
  294. package/dist/types/init/utils/index.d.ts +2 -2
  295. package/dist/types/init/utils/packageManager.d.ts +39 -6
  296. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  297. package/package.json +10 -10
@@ -115,12 +115,16 @@ var DictionariesLogger = class {
115
115
  const isLocalDone = localDone === localTotal;
116
116
  const isRemoteDone = remoteDone === remoteTotal;
117
117
  const isPluginDone = pluginDone === pluginTotal;
118
- if (!(this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0)) if (isLocalDone) lines.push(`${this.prefix} ${_intlayer_config_logger.v} Local content: ${(0, _intlayer_config_logger.colorize)(`${localDone}`, _intlayer_config_colors.GREEN)}${(0, _intlayer_config_logger.colorize)(`/${localTotal}`, _intlayer_config_colors.GREY)}`);
119
- else lines.push(`${this.prefix} ${clock} Local content: ${(0, _intlayer_config_logger.colorize)(`${localDone}`, _intlayer_config_colors.BLUE)}${(0, _intlayer_config_logger.colorize)(`/${localTotal}`, _intlayer_config_colors.GREY)}`);
120
- if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) if (this.remoteError) lines.push(`${this.prefix} ${_intlayer_config_logger.x} Remote content: ${(0, _intlayer_config_logger.colorize)(this.remoteError, _intlayer_config_colors.RED)}`);
121
- else if (remoteTotal === 0) lines.push(`${this.prefix} ${clock} Remote content: ${(0, _intlayer_config_logger.colorize)("Check server", _intlayer_config_colors.BLUE)}`);
122
- else if (isRemoteDone) lines.push(`${this.prefix} ${_intlayer_config_logger.v} Remote content: ${(0, _intlayer_config_logger.colorize)(`${remoteDone}`, _intlayer_config_colors.GREEN)}${(0, _intlayer_config_logger.colorize)(`/${remoteTotal}`, _intlayer_config_colors.GREY)}`);
123
- else lines.push(`${this.prefix} ${clock} Remote content: ${(0, _intlayer_config_logger.colorize)(`${remoteDone}`, _intlayer_config_colors.BLUE)}${(0, _intlayer_config_logger.colorize)(`/${remoteTotal}`, _intlayer_config_colors.GREY)}`);
118
+ if (!(this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0)) {
119
+ if (isLocalDone) lines.push(`${this.prefix} ${_intlayer_config_logger.v} Local content: ${(0, _intlayer_config_logger.colorize)(`${localDone}`, _intlayer_config_colors.GREEN)}${(0, _intlayer_config_logger.colorize)(`/${localTotal}`, _intlayer_config_colors.GREY)}`);
120
+ else lines.push(`${this.prefix} ${clock} Local content: ${(0, _intlayer_config_logger.colorize)(`${localDone}`, _intlayer_config_colors.BLUE)}${(0, _intlayer_config_logger.colorize)(`/${localTotal}`, _intlayer_config_colors.GREY)}`);
121
+ }
122
+ if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {
123
+ if (this.remoteError) lines.push(`${this.prefix} ${_intlayer_config_logger.x} Remote content: ${(0, _intlayer_config_logger.colorize)(this.remoteError, _intlayer_config_colors.RED)}`);
124
+ else if (remoteTotal === 0) lines.push(`${this.prefix} ${clock} Remote content: ${(0, _intlayer_config_logger.colorize)("Check server", _intlayer_config_colors.BLUE)}`);
125
+ else if (isRemoteDone) lines.push(`${this.prefix} ${_intlayer_config_logger.v} Remote content: ${(0, _intlayer_config_logger.colorize)(`${remoteDone}`, _intlayer_config_colors.GREEN)}${(0, _intlayer_config_logger.colorize)(`/${remoteTotal}`, _intlayer_config_colors.GREY)}`);
126
+ else lines.push(`${this.prefix} ${clock} Remote content: ${(0, _intlayer_config_logger.colorize)(`${remoteDone}`, _intlayer_config_colors.BLUE)}${(0, _intlayer_config_logger.colorize)(`/${remoteTotal}`, _intlayer_config_colors.GREY)}`);
127
+ }
124
128
  if (pluginTotal > 0 || this.pluginError) {
125
129
  const pluginNamesSuffix = this.pluginNames.length > 0 ? (0, _intlayer_config_logger.colorize)(` (${this.pluginNames.join(", ")})`, _intlayer_config_colors.GREY) : "";
126
130
  if (this.pluginError) lines.push(`${this.prefix} ${_intlayer_config_logger.x} Plugin content: ${(0, _intlayer_config_logger.colorize)(this.pluginError, _intlayer_config_colors.RED)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"log.cjs","names":["spinnerFrames","log","ANSIColors","v","x"],"sources":["../../../src/loadDictionaries/log.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n getPrefix,\n spinnerFrames,\n v,\n x,\n} from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport class DictionariesLogger {\n private statuses: DictionariesStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n private remoteCheckInProgress = false;\n private expectRemote = false;\n private remoteError: string | undefined;\n private pluginTotal = 0;\n private pluginDone = 0;\n private pluginNames: string[] = [];\n private pluginError: string | undefined;\n\n constructor() {\n this.prefix = getPrefix(log?.prefix) ?? '';\n }\n\n setExpectRemote(expect: boolean) {\n this.expectRemote = expect;\n }\n\n startRemoteCheck() {\n if (this.isFinished) return;\n this.remoteCheckInProgress = true;\n this.startSpinner();\n this.render();\n }\n\n stopRemoteCheck() {\n this.remoteCheckInProgress = false;\n }\n\n update(newStatuses: DictionariesStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) =>\n s.dictionaryKey === status.dictionaryKey && s.type === status.type\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n // If we expect remote fetch later, avoid rendering a local-only line first\n const { remoteTotal } = this.computeProgress();\n if (this.expectRemote && !this.remoteCheckInProgress && remoteTotal === 0) {\n // Do not start spinner or render yet; wait until remote check starts\n return;\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n // Render final state and keep it visible\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n public setRemoteError = (error?: Error) => {\n this.remoteError = extractErrorMessage(error);\n // Avoid rendering a transient remote-only line while the remote check flag is still true\n // Ensure local + remote are rendered together after a failure\n this.stopRemoteCheck();\n this.render();\n };\n\n /**\n * Register the names of the plugins providing dictionaries.\n * They are displayed next to the plugin progress counters, e.g.\n * `Plugin content: 6/6 (sync-json, load-po)`.\n *\n * @param names - Names of the plugins exposing a `loadDictionaries` hook\n */\n setPluginNames(names: string[]) {\n if (this.isFinished) return;\n // Guard against plugins declared without a name at runtime\n this.pluginNames = names.filter((name) => Boolean(name));\n this.render();\n }\n\n setPluginTotal(total: number) {\n if (this.isFinished) return;\n this.pluginTotal = total;\n if (total > 0) {\n this.startSpinner();\n }\n this.render();\n }\n\n setPluginDone(done: number) {\n if (this.isFinished) return;\n this.pluginDone = done;\n this.render();\n }\n\n /**\n * Flag the plugin line as errored.\n *\n * @param error - Error thrown while loading the plugin dictionaries\n * @param pluginName - Name of the plugin that threw, prefixed to the message\n */\n setPluginError(error?: Error, pluginName?: string) {\n if (this.isFinished) return;\n const errorMessage = extractErrorMessage(error);\n this.pluginError = pluginName\n ? `${pluginName}: ${errorMessage}`\n : errorMessage;\n this.render();\n }\n\n private render() {\n const {\n localTotal,\n localDone,\n remoteTotal,\n remoteDone,\n pluginTotal,\n pluginDone,\n } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const clock = colorize(frame, ANSIColors.BLUE);\n const lines: string[] = [];\n\n const isLocalDone = localDone === localTotal;\n const isRemoteDone = remoteDone === remoteTotal;\n const isPluginDone = pluginDone === pluginTotal;\n\n const suppressLocalWhileCheckingRemote =\n this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0;\n\n if (!suppressLocalWhileCheckingRemote) {\n if (isLocalDone) {\n lines.push(\n `${this.prefix} ${v} Local content: ${colorize(`${localDone}`, ANSIColors.GREEN)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Local content: ${colorize(`${localDone}`, ANSIColors.BLUE)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Single remote line: show error, check, or progress counts\n if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {\n if (this.remoteError) {\n lines.push(\n `${this.prefix} ${x} Remote content: ${colorize(\n this.remoteError,\n ANSIColors.RED\n )}`\n );\n } else if (remoteTotal === 0) {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize('Check server', ANSIColors.BLUE)}`\n );\n } else if (isRemoteDone) {\n lines.push(\n `${this.prefix} ${v} Remote content: ${colorize(`${remoteDone}`, ANSIColors.GREEN)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize(`${remoteDone}`, ANSIColors.BLUE)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Plugin line: show error or progress counts, suffixed by the plugin names\n if (pluginTotal > 0 || this.pluginError) {\n const pluginNamesSuffix =\n this.pluginNames.length > 0\n ? colorize(` (${this.pluginNames.join(', ')})`, ANSIColors.GREY)\n : '';\n\n if (this.pluginError) {\n lines.push(\n `${this.prefix} ${x} Plugin content: ${colorize(\n this.pluginError,\n ANSIColors.RED\n )}`\n );\n } else if (isPluginDone) {\n lines.push(\n `${this.prefix} ${v} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.GREEN)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.BLUE)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n }\n }\n\n // Check if the state has changed to avoid duplicate rendering\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const localKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'local')\n .map((s) => s.dictionaryKey)\n );\n\n const localDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'local' && (s.status === 'built' || s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n const remoteKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'remote')\n .map((s) => s.dictionaryKey)\n );\n\n const remoteDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'remote' &&\n (s.status === 'fetched' ||\n s.status === 'imported' ||\n s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n return {\n localTotal: localKeys.size,\n localDone: localDoneKeys.size,\n remoteTotal: remoteKeys.size,\n remoteDone: remoteDoneKeys.size,\n pluginTotal: this.pluginTotal,\n pluginDone: this.pluginDone,\n } as const;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"log.cjs","names":["spinnerFrames","getPrefix","log","extractErrorMessage","colorize","ANSIColors","v","x"],"sources":["../../../src/loadDictionaries/log.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n getPrefix,\n spinnerFrames,\n v,\n x,\n} from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport class DictionariesLogger {\n private statuses: DictionariesStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n private remoteCheckInProgress = false;\n private expectRemote = false;\n private remoteError: string | undefined;\n private pluginTotal = 0;\n private pluginDone = 0;\n private pluginNames: string[] = [];\n private pluginError: string | undefined;\n\n constructor() {\n this.prefix = getPrefix(log?.prefix) ?? '';\n }\n\n setExpectRemote(expect: boolean) {\n this.expectRemote = expect;\n }\n\n startRemoteCheck() {\n if (this.isFinished) return;\n this.remoteCheckInProgress = true;\n this.startSpinner();\n this.render();\n }\n\n stopRemoteCheck() {\n this.remoteCheckInProgress = false;\n }\n\n update(newStatuses: DictionariesStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) =>\n s.dictionaryKey === status.dictionaryKey && s.type === status.type\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n // If we expect remote fetch later, avoid rendering a local-only line first\n const { remoteTotal } = this.computeProgress();\n if (this.expectRemote && !this.remoteCheckInProgress && remoteTotal === 0) {\n // Do not start spinner or render yet; wait until remote check starts\n return;\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n // Render final state and keep it visible\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n public setRemoteError = (error?: Error) => {\n this.remoteError = extractErrorMessage(error);\n // Avoid rendering a transient remote-only line while the remote check flag is still true\n // Ensure local + remote are rendered together after a failure\n this.stopRemoteCheck();\n this.render();\n };\n\n /**\n * Register the names of the plugins providing dictionaries.\n * They are displayed next to the plugin progress counters, e.g.\n * `Plugin content: 6/6 (sync-json, load-po)`.\n *\n * @param names - Names of the plugins exposing a `loadDictionaries` hook\n */\n setPluginNames(names: string[]) {\n if (this.isFinished) return;\n // Guard against plugins declared without a name at runtime\n this.pluginNames = names.filter((name) => Boolean(name));\n this.render();\n }\n\n setPluginTotal(total: number) {\n if (this.isFinished) return;\n this.pluginTotal = total;\n if (total > 0) {\n this.startSpinner();\n }\n this.render();\n }\n\n setPluginDone(done: number) {\n if (this.isFinished) return;\n this.pluginDone = done;\n this.render();\n }\n\n /**\n * Flag the plugin line as errored.\n *\n * @param error - Error thrown while loading the plugin dictionaries\n * @param pluginName - Name of the plugin that threw, prefixed to the message\n */\n setPluginError(error?: Error, pluginName?: string) {\n if (this.isFinished) return;\n const errorMessage = extractErrorMessage(error);\n this.pluginError = pluginName\n ? `${pluginName}: ${errorMessage}`\n : errorMessage;\n this.render();\n }\n\n private render() {\n const {\n localTotal,\n localDone,\n remoteTotal,\n remoteDone,\n pluginTotal,\n pluginDone,\n } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const clock = colorize(frame, ANSIColors.BLUE);\n const lines: string[] = [];\n\n const isLocalDone = localDone === localTotal;\n const isRemoteDone = remoteDone === remoteTotal;\n const isPluginDone = pluginDone === pluginTotal;\n\n const suppressLocalWhileCheckingRemote =\n this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0;\n\n if (!suppressLocalWhileCheckingRemote) {\n if (isLocalDone) {\n lines.push(\n `${this.prefix} ${v} Local content: ${colorize(`${localDone}`, ANSIColors.GREEN)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Local content: ${colorize(`${localDone}`, ANSIColors.BLUE)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Single remote line: show error, check, or progress counts\n if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {\n if (this.remoteError) {\n lines.push(\n `${this.prefix} ${x} Remote content: ${colorize(\n this.remoteError,\n ANSIColors.RED\n )}`\n );\n } else if (remoteTotal === 0) {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize('Check server', ANSIColors.BLUE)}`\n );\n } else if (isRemoteDone) {\n lines.push(\n `${this.prefix} ${v} Remote content: ${colorize(`${remoteDone}`, ANSIColors.GREEN)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize(`${remoteDone}`, ANSIColors.BLUE)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Plugin line: show error or progress counts, suffixed by the plugin names\n if (pluginTotal > 0 || this.pluginError) {\n const pluginNamesSuffix =\n this.pluginNames.length > 0\n ? colorize(` (${this.pluginNames.join(', ')})`, ANSIColors.GREY)\n : '';\n\n if (this.pluginError) {\n lines.push(\n `${this.prefix} ${x} Plugin content: ${colorize(\n this.pluginError,\n ANSIColors.RED\n )}`\n );\n } else if (isPluginDone) {\n lines.push(\n `${this.prefix} ${v} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.GREEN)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.BLUE)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n }\n }\n\n // Check if the state has changed to avoid duplicate rendering\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const localKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'local')\n .map((s) => s.dictionaryKey)\n );\n\n const localDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'local' && (s.status === 'built' || s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n const remoteKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'remote')\n .map((s) => s.dictionaryKey)\n );\n\n const remoteDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'remote' &&\n (s.status === 'fetched' ||\n s.status === 'imported' ||\n s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n return {\n localTotal: localKeys.size,\n localDone: localDoneKeys.size,\n remoteTotal: remoteKeys.size,\n remoteDone: remoteDoneKeys.size,\n pluginTotal: this.pluginTotal,\n pluginDone: this.pluginDone,\n } as const;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logTypeScriptErrors.cjs","names":[],"sources":["../../../src/loadDictionaries/logTypeScriptErrors.ts"],"sourcesContent":["import { dirname, extname } from 'node:path';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\nexport const logTypeScriptErrors = async (\n filePaths: string[],\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n\n const filesToCheck = filePaths.filter((path) => {\n const ext = extname(path);\n\n return ['.ts', '.tsx', '.js', '.jsx', '.cjs', '.mjs', '.json'].includes(\n ext\n );\n });\n\n if (filesToCheck.length === 0) return;\n\n let ts: typeof import('typescript');\n\n try {\n ts = (await import('typescript')).default || (await import('typescript'));\n } catch {\n // TypeScript not installed, skip type checking\n\n return;\n }\n\n const configFileName = ts.findConfigFile(\n configuration.system?.baseDir ?? process.cwd(),\n ts.sys.fileExists,\n 'tsconfig.json'\n );\n\n let compilerOptions: any = {\n noEmit: true,\n\n allowJs: true,\n\n resolveJsonModule: true,\n };\n\n if (configFileName) {\n const configFileText = ts.sys.readFile(configFileName);\n\n if (configFileText) {\n const configJson = ts.parseConfigFileTextToJson(\n configFileName,\n\n configFileText\n );\n\n if (!configJson.error) {\n const parsedConfig = ts.parseJsonConfigFileContent(\n configJson.config,\n\n ts.sys,\n\n dirname(configFileName)\n );\n\n const { incremental, tsBuildInfoFile, ...restOptions } =\n parsedConfig.options;\n\n compilerOptions = { ...compilerOptions, ...restOptions, noEmit: true };\n }\n }\n }\n\n const program = ts.createProgram(filesToCheck, compilerOptions);\n\n filesToCheck.forEach((filePath) => {\n const sourceFile = program.getSourceFile(filePath);\n\n if (!sourceFile) return;\n\n const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);\n\n diagnostics.forEach((diagnostic) => {\n const message = ts.flattenDiagnosticMessageText(\n diagnostic.messageText,\n\n '\\n'\n );\n\n if (diagnostic.file && diagnostic.start !== undefined) {\n const { line, character } =\n diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n\n appLogger(\n `TS Error in ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`,\n\n { level: 'warn' }\n );\n }\n });\n });\n};\n"],"mappings":";;;;;AAIA,MAAa,sBAAsB,OACjC,WACA,kBACG;CACH,MAAM,sDAAyB,aAAa;CAE5C,MAAM,eAAe,UAAU,QAAQ,SAAS;EAC9C,MAAM,6BAAc,IAAI;EAExB,OAAO;GAAC;GAAO;GAAQ;GAAO;GAAQ;GAAQ;GAAQ;EAAO,CAAC,CAAC,SAC7D,GACF;CACF,CAAC;CAED,IAAI,aAAa,WAAW,GAAG;CAE/B,IAAI;CAEJ,IAAI;EACF,MAAM,MAAM,OAAO,cAAa,CAAE,WAAY,MAAM,OAAO;CAC7D,QAAQ;EAGN;CACF;CAEA,MAAM,iBAAiB,GAAG,eACxB,cAAc,QAAQ,WAAW,QAAQ,IAAI,GAC7C,GAAG,IAAI,YACP,eACF;CAEA,IAAI,kBAAuB;EACzB,QAAQ;EAER,SAAS;EAET,mBAAmB;CACrB;CAEA,IAAI,gBAAgB;EAClB,MAAM,iBAAiB,GAAG,IAAI,SAAS,cAAc;EAErD,IAAI,gBAAgB;GAClB,MAAM,aAAa,GAAG,0BACpB,gBAEA,cACF;GAEA,IAAI,CAAC,WAAW,OAAO;IASrB,MAAM,EAAE,aAAa,iBAAiB,GAAG,gBARpB,GAAG,2BACtB,WAAW,QAEX,GAAG,4BAEK,cAAc,CAIX,CAAC,CAAC;IAEf,kBAAkB;KAAE,GAAG;KAAiB,GAAG;KAAa,QAAQ;IAAK;GACvE;EACF;CACF;CAEA,MAAM,UAAU,GAAG,cAAc,cAAc,eAAe;CAE9D,aAAa,SAAS,aAAa;EACjC,MAAM,aAAa,QAAQ,cAAc,QAAQ;EAEjD,IAAI,CAAC,YAAY;EAIjB,AAFoB,GAAG,sBAAsB,SAAS,UAE5C,CAAC,CAAC,SAAS,eAAe;GAClC,MAAM,UAAU,GAAG,6BACjB,WAAW,aAEX,IACF;GAEA,IAAI,WAAW,QAAQ,WAAW,UAAU,QAAW;IACrD,MAAM,EAAE,MAAM,cACZ,WAAW,KAAK,8BAA8B,WAAW,KAAK;IAEhE,UACE,eAAe,WAAW,KAAK,SAAS,IAAI,OAAO,EAAE,GAAG,YAAY,EAAE,KAAK,WAE3E,EAAE,OAAO,OAAO,CAClB;GACF;EACF,CAAC;CACH,CAAC;AACH"}
1
+ {"version":3,"file":"logTypeScriptErrors.cjs","names":["getAppLogger","extname","dirname"],"sources":["../../../src/loadDictionaries/logTypeScriptErrors.ts"],"sourcesContent":["import { dirname, extname } from 'node:path';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\nexport const logTypeScriptErrors = async (\n filePaths: string[],\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n\n const filesToCheck = filePaths.filter((path) => {\n const ext = extname(path);\n\n return ['.ts', '.tsx', '.js', '.jsx', '.cjs', '.mjs', '.json'].includes(\n ext\n );\n });\n\n if (filesToCheck.length === 0) return;\n\n let ts: typeof import('typescript');\n\n try {\n ts = (await import('typescript')).default || (await import('typescript'));\n } catch {\n // TypeScript not installed, skip type checking\n\n return;\n }\n\n const configFileName = ts.findConfigFile(\n configuration.system?.baseDir ?? process.cwd(),\n ts.sys.fileExists,\n 'tsconfig.json'\n );\n\n let compilerOptions: any = {\n noEmit: true,\n\n allowJs: true,\n\n resolveJsonModule: true,\n };\n\n if (configFileName) {\n const configFileText = ts.sys.readFile(configFileName);\n\n if (configFileText) {\n const configJson = ts.parseConfigFileTextToJson(\n configFileName,\n\n configFileText\n );\n\n if (!configJson.error) {\n const parsedConfig = ts.parseJsonConfigFileContent(\n configJson.config,\n\n ts.sys,\n\n dirname(configFileName)\n );\n\n const { incremental, tsBuildInfoFile, ...restOptions } =\n parsedConfig.options;\n\n compilerOptions = { ...compilerOptions, ...restOptions, noEmit: true };\n }\n }\n }\n\n const program = ts.createProgram(filesToCheck, compilerOptions);\n\n filesToCheck.forEach((filePath) => {\n const sourceFile = program.getSourceFile(filePath);\n\n if (!sourceFile) return;\n\n const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);\n\n diagnostics.forEach((diagnostic) => {\n const message = ts.flattenDiagnosticMessageText(\n diagnostic.messageText,\n\n '\\n'\n );\n\n if (diagnostic.file && diagnostic.start !== undefined) {\n const { line, character } =\n diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n\n appLogger(\n `TS Error in ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`,\n\n { level: 'warn' }\n );\n }\n });\n });\n};\n"],"mappings":";;;;;AAIA,MAAa,sBAAsB,OACjC,WACA,kBACG;CACH,MAAM,gBAAYA,sCAAa,aAAa;CAE5C,MAAM,eAAe,UAAU,QAAQ,SAAS;EAC9C,MAAM,UAAMC,mBAAQ,IAAI;EAExB,OAAO;GAAC;GAAO;GAAQ;GAAO;GAAQ;GAAQ;GAAQ;EAAO,CAAC,CAAC,SAC7D,GACF;CACF,CAAC;CAED,IAAI,aAAa,WAAW,GAAG;CAE/B,IAAI;CAEJ,IAAI;EACF,MAAM,MAAM,OAAO,cAAa,CAAE,WAAY,MAAM,OAAO;CAC7D,QAAQ;EAGN;CACF;CAEA,MAAM,iBAAiB,GAAG,eACxB,cAAc,QAAQ,WAAW,QAAQ,IAAI,GAC7C,GAAG,IAAI,YACP,eACF;CAEA,IAAI,kBAAuB;EACzB,QAAQ;EAER,SAAS;EAET,mBAAmB;CACrB;CAEA,IAAI,gBAAgB;EAClB,MAAM,iBAAiB,GAAG,IAAI,SAAS,cAAc;EAErD,IAAI,gBAAgB;GAClB,MAAM,aAAa,GAAG,0BACpB,gBAEA,cACF;GAEA,IAAI,CAAC,WAAW,OAAO;IASrB,MAAM,EAAE,aAAa,iBAAiB,GAAG,gBARpB,GAAG,2BACtB,WAAW,QAEX,GAAG,SAEHC,mBAAQ,cAAc,CAIX,CAAC,CAAC;IAEf,kBAAkB;KAAE,GAAG;KAAiB,GAAG;KAAa,QAAQ;IAAK;GACvE;EACF;CACF;CAEA,MAAM,UAAU,GAAG,cAAc,cAAc,eAAe;CAE9D,aAAa,SAAS,aAAa;EACjC,MAAM,aAAa,QAAQ,cAAc,QAAQ;EAEjD,IAAI,CAAC,YAAY;EAIjB,AAFoB,GAAG,sBAAsB,SAAS,UAE5C,CAAC,CAAC,SAAS,eAAe;GAClC,MAAM,UAAU,GAAG,6BACjB,WAAW,aAEX,IACF;GAEA,IAAI,WAAW,QAAQ,WAAW,UAAU,QAAW;IACrD,MAAM,EAAE,MAAM,cACZ,WAAW,KAAK,8BAA8B,WAAW,KAAK;IAEhE,UACE,eAAe,WAAW,KAAK,SAAS,IAAI,OAAO,EAAE,GAAG,YAAY,EAAE,KAAK,WAE3E,EAAE,OAAO,OAAO,CAClB;GACF;EACF,CAAC;CACH,CAAC;AACH"}
@@ -26,16 +26,17 @@ const logConfigDetails = (options) => {
26
26
  if (customConfiguration) {
27
27
  const validation = _intlayer_config_node.intlayerConfigSchema.safeParse(customConfiguration);
28
28
  if (!validation.success) {
29
- const errorMessage = `${_intlayer_config_logger.x} Invalid configuration:\n${validation.error.issues.map((error) => {
29
+ const errorMessages = validation.error.issues.map((error) => {
30
30
  return `${(0, _intlayer_config_logger.colorizePath)(` - ${error.path.join(".")}:`)} ${(0, _intlayer_config_logger.colorize)(error.message, _intlayer_config_colors.GREY_DARK)}`;
31
- }).join("\n")}`;
31
+ }).join("\n");
32
+ const errorMessage = `${_intlayer_config_logger.x} Invalid configuration:\n${errorMessages}`;
32
33
  appLogger(errorMessage);
33
34
  }
34
35
  if (customConfiguration.build?.importMode) appLogger(`${(0, _intlayer_config_logger.colorize)("build.importMode", _intlayer_config_colors.BLUE)} is deprecated, use ${(0, _intlayer_config_logger.colorize)("dictionary.importMode", _intlayer_config_colors.BLUE)} instead`);
35
36
  if (customConfiguration.compiler?.transformPattern) appLogger(`${(0, _intlayer_config_logger.colorize)("compiler.transformPattern", _intlayer_config_colors.BLUE)} is deprecated, use ${(0, _intlayer_config_logger.colorize)("build.traversePattern", _intlayer_config_colors.BLUE)} instead`);
36
37
  if (customConfiguration.compiler?.excludePattern) appLogger(`${(0, _intlayer_config_logger.colorize)("compiler.excludePattern", _intlayer_config_colors.BLUE)} is deprecated, use ${(0, _intlayer_config_logger.colorize)("build.traversePattern", _intlayer_config_colors.BLUE)} instead`);
37
38
  }
38
- }, { cacheTimeoutMs: 1e3 * 60 });
39
+ }, { cacheTimeoutMs: 6e4 });
39
40
  };
40
41
 
41
42
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"logConfigDetails.cjs","names":["formatPath","intlayerConfigSchema","x","ANSIColors"],"sources":["../../src/logConfigDetails.ts"],"sourcesContent":["import { join, relative } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { getEnvFilePath } from '@intlayer/config/env';\nimport {\n colorize,\n colorizePath,\n getAppLogger,\n x,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfigurationAndFilePath,\n intlayerConfigSchema,\n} from '@intlayer/config/node';\nimport { formatPath, runOnce } from './utils';\n\nexport const logConfigDetails = (options?: GetConfigurationOptions) => {\n const {\n configuration,\n customConfiguration,\n numCustomConfiguration,\n configurationFilePath,\n } = getConfigurationAndFilePath(options);\n const appLogger = getAppLogger(configuration);\n\n runOnce(\n join(\n configuration.system.baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-config-locaded.lock'\n ),\n () => {\n if (numCustomConfiguration === 0) {\n appLogger(\n 'Configuration file not found, using default configuration.',\n {\n isVerbose: true,\n }\n );\n } else {\n const baseDir = configuration.system.baseDir;\n const relativeOutputPath = relative(baseDir, configurationFilePath!);\n\n if (numCustomConfiguration === 1) {\n const dotEnvFilePath = getEnvFilePath(options?.env, options?.envFile);\n\n appLogger(\n `Configuration loaded ${formatPath(relativeOutputPath)}${dotEnvFilePath ? ` - Env: ${formatPath(dotEnvFilePath)}` : ''}`,\n {\n isVerbose: true,\n }\n );\n } else {\n appLogger(\n `Multiple configuration files found, using ${formatPath(relativeOutputPath)}.`,\n {\n isVerbose: true,\n }\n );\n }\n }\n\n if (customConfiguration) {\n const validation = intlayerConfigSchema.safeParse(customConfiguration);\n\n if (!validation.success) {\n const errorMessages = validation.error.issues\n .map((error) => {\n const path = colorizePath(` - ${error.path.join('.')}:`);\n const message = colorize(error.message, ANSIColors.GREY_DARK);\n return `${path} ${message}`;\n })\n .join('\\n');\n const errorMessage = `${x} Invalid configuration:\\n${errorMessages}`;\n\n appLogger(errorMessage);\n }\n\n if (customConfiguration.build?.importMode) {\n appLogger(\n `${colorize('build.importMode', ANSIColors.BLUE)} is deprecated, use ${colorize('dictionary.importMode', ANSIColors.BLUE)} instead`\n );\n }\n if (customConfiguration.compiler?.transformPattern) {\n appLogger(\n `${colorize('compiler.transformPattern', ANSIColors.BLUE)} is deprecated, use ${colorize('build.traversePattern', ANSIColors.BLUE)} instead`\n );\n }\n if (customConfiguration.compiler?.excludePattern) {\n appLogger(\n `${colorize('compiler.excludePattern', ANSIColors.BLUE)} is deprecated, use ${colorize('build.traversePattern', ANSIColors.BLUE)} instead`\n );\n }\n }\n },\n {\n cacheTimeoutMs: 1000 * 60, // 1 minute\n }\n );\n};\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAa,oBAAoB,YAAsC;CACrE,MAAM,EACJ,eACA,qBACA,wBACA,iFAC8B,OAAO;CACvC,MAAM,sDAAyB,aAAa;CAE5C,kDAEI,cAAc,OAAO,SACrB,aACA,SACA,8BACF,SACM;EACJ,IAAI,2BAA2B,GAC7B,UACE,8DACA,EACE,WAAW,KACb,CACF;OACK;GACL,MAAM,UAAU,cAAc,OAAO;GACrC,MAAM,6CAA8B,SAAS,qBAAsB;GAEnE,IAAI,2BAA2B,GAAG;IAChC,MAAM,0DAAgC,SAAS,KAAK,SAAS,OAAO;IAEpE,UACE,wBAAwBA,mCAAW,kBAAkB,IAAI,iBAAiB,WAAWA,mCAAW,cAAc,MAAM,MACpH,EACE,WAAW,KACb,CACF;GACF,OACE,UACE,6CAA6CA,mCAAW,kBAAkB,EAAE,IAC5E,EACE,WAAW,KACb,CACF;EAEJ;EAEA,IAAI,qBAAqB;GACvB,MAAM,aAAaC,2CAAqB,UAAU,mBAAmB;GAErE,IAAI,CAAC,WAAW,SAAS;IAQvB,MAAM,eAAe,GAAGC,0BAAE,2BAPJ,WAAW,MAAM,OACpC,KAAK,UAAU;KAGd,OAAO,6CAFmB,MAAM,MAAM,KAAK,KAAK,GAAG,EAAE,EAExC,EAAE,yCADU,MAAM,SAASC,wBAAW,SAC3B;IAC1B,CAAC,CAAC,CACD,KAAK,IACyD;IAEjE,UAAU,YAAY;GACxB;GAEA,IAAI,oBAAoB,OAAO,YAC7B,UACE,yCAAY,oBAAoBA,wBAAW,IAAI,EAAE,4DAA+B,yBAAyBA,wBAAW,IAAI,EAAE,SAC5H;GAEF,IAAI,oBAAoB,UAAU,kBAChC,UACE,yCAAY,6BAA6BA,wBAAW,IAAI,EAAE,4DAA+B,yBAAyBA,wBAAW,IAAI,EAAE,SACrI;GAEF,IAAI,oBAAoB,UAAU,gBAChC,UACE,yCAAY,2BAA2BA,wBAAW,IAAI,EAAE,4DAA+B,yBAAyBA,wBAAW,IAAI,EAAE,SACnI;EAEJ;CACF,GACA,EACE,gBAAgB,MAAO,GACzB,CACF;AACF"}
1
+ {"version":3,"file":"logConfigDetails.cjs","names":["getConfigurationAndFilePath","getAppLogger","join","relative","getEnvFilePath","formatPath","intlayerConfigSchema","colorizePath","colorize","ANSIColors","x"],"sources":["../../src/logConfigDetails.ts"],"sourcesContent":["import { join, relative } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { getEnvFilePath } from '@intlayer/config/env';\nimport {\n colorize,\n colorizePath,\n getAppLogger,\n x,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfigurationAndFilePath,\n intlayerConfigSchema,\n} from '@intlayer/config/node';\nimport { formatPath, runOnce } from './utils';\n\nexport const logConfigDetails = (options?: GetConfigurationOptions) => {\n const {\n configuration,\n customConfiguration,\n numCustomConfiguration,\n configurationFilePath,\n } = getConfigurationAndFilePath(options);\n const appLogger = getAppLogger(configuration);\n\n runOnce(\n join(\n configuration.system.baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-config-locaded.lock'\n ),\n () => {\n if (numCustomConfiguration === 0) {\n appLogger(\n 'Configuration file not found, using default configuration.',\n {\n isVerbose: true,\n }\n );\n } else {\n const baseDir = configuration.system.baseDir;\n const relativeOutputPath = relative(baseDir, configurationFilePath!);\n\n if (numCustomConfiguration === 1) {\n const dotEnvFilePath = getEnvFilePath(options?.env, options?.envFile);\n\n appLogger(\n `Configuration loaded ${formatPath(relativeOutputPath)}${dotEnvFilePath ? ` - Env: ${formatPath(dotEnvFilePath)}` : ''}`,\n {\n isVerbose: true,\n }\n );\n } else {\n appLogger(\n `Multiple configuration files found, using ${formatPath(relativeOutputPath)}.`,\n {\n isVerbose: true,\n }\n );\n }\n }\n\n if (customConfiguration) {\n const validation = intlayerConfigSchema.safeParse(customConfiguration);\n\n if (!validation.success) {\n const errorMessages = validation.error.issues\n .map((error) => {\n const path = colorizePath(` - ${error.path.join('.')}:`);\n const message = colorize(error.message, ANSIColors.GREY_DARK);\n return `${path} ${message}`;\n })\n .join('\\n');\n const errorMessage = `${x} Invalid configuration:\\n${errorMessages}`;\n\n appLogger(errorMessage);\n }\n\n if (customConfiguration.build?.importMode) {\n appLogger(\n `${colorize('build.importMode', ANSIColors.BLUE)} is deprecated, use ${colorize('dictionary.importMode', ANSIColors.BLUE)} instead`\n );\n }\n if (customConfiguration.compiler?.transformPattern) {\n appLogger(\n `${colorize('compiler.transformPattern', ANSIColors.BLUE)} is deprecated, use ${colorize('build.traversePattern', ANSIColors.BLUE)} instead`\n );\n }\n if (customConfiguration.compiler?.excludePattern) {\n appLogger(\n `${colorize('compiler.excludePattern', ANSIColors.BLUE)} is deprecated, use ${colorize('build.traversePattern', ANSIColors.BLUE)} instead`\n );\n }\n }\n },\n {\n cacheTimeoutMs: 1000 * 60, // 1 minute\n }\n );\n};\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAa,oBAAoB,YAAsC;CACrE,MAAM,EACJ,eACA,qBACA,wBACA,8BACEA,mDAA4B,OAAO;CACvC,MAAM,gBAAYC,sCAAa,aAAa;CAE5C,kCACEC,gBACE,cAAc,OAAO,SACrB,aACA,SACA,8BACF,SACM;EACJ,IAAI,2BAA2B,GAC7B,UACE,8DACA,EACE,WAAW,KACb,CACF;OACK;GACL,MAAM,UAAU,cAAc,OAAO;GACrC,MAAM,yBAAqBC,oBAAS,SAAS,qBAAsB;GAEnE,IAAI,2BAA2B,GAAG;IAChC,MAAM,qBAAiBC,qCAAe,SAAS,KAAK,SAAS,OAAO;IAEpE,UACE,wBAAwBC,mCAAW,kBAAkB,IAAI,iBAAiB,WAAWA,mCAAW,cAAc,MAAM,MACpH,EACE,WAAW,KACb,CACF;GACF,OACE,UACE,6CAA6CA,mCAAW,kBAAkB,EAAE,IAC5E,EACE,WAAW,KACb,CACF;EAEJ;EAEA,IAAI,qBAAqB;GACvB,MAAM,aAAaC,2CAAqB,UAAU,mBAAmB;GAErE,IAAI,CAAC,WAAW,SAAS;IACvB,MAAM,gBAAgB,WAAW,MAAM,OACpC,KAAK,UAAU;KAGd,OAAO,OAFMC,sCAAa,MAAM,MAAM,KAAK,KAAK,GAAG,EAAE,EAExC,EAAE,OADCC,kCAAS,MAAM,SAASC,wBAAW,SAC3B;IAC1B,CAAC,CAAC,CACD,KAAK,IAAI;IACZ,MAAM,eAAe,GAAGC,0BAAE,2BAA2B;IAErD,UAAU,YAAY;GACxB;GAEA,IAAI,oBAAoB,OAAO,YAC7B,UACE,OAAGF,kCAAS,oBAAoBC,wBAAW,IAAI,EAAE,0BAAsBD,kCAAS,yBAAyBC,wBAAW,IAAI,EAAE,SAC5H;GAEF,IAAI,oBAAoB,UAAU,kBAChC,UACE,OAAGD,kCAAS,6BAA6BC,wBAAW,IAAI,EAAE,0BAAsBD,kCAAS,yBAAyBC,wBAAW,IAAI,EAAE,SACrI;GAEF,IAAI,oBAAoB,UAAU,gBAChC,UACE,OAAGD,kCAAS,2BAA2BC,wBAAW,IAAI,EAAE,0BAAsBD,kCAAS,yBAAyBC,wBAAW,IAAI,EAAE,SACnI;EAEJ;CACF,GACA,EACE,gBAAgB,IAClB,CACF;AACF"}
@@ -24,7 +24,7 @@ const DEFAULT_PREPARE_INTLAYER_OPTIONS = {
24
24
  clean: false,
25
25
  env: "dev",
26
26
  format: ["cjs", "esm"],
27
- cacheTimeoutMs: 1e3 * 60 * 60
27
+ cacheTimeoutMs: 36e5
28
28
  };
29
29
  const prepareIntlayer = async (configuration, options) => {
30
30
  const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
@@ -57,7 +57,8 @@ const prepareIntlayer = async (configuration, options) => {
57
57
  await require_writeConfiguration_index.writeConfiguration(configuration);
58
58
  const configurationWrittenTime = Date.now();
59
59
  appLogger(["Configuration written", (0, _intlayer_config_logger.colorize)(`(${configurationWrittenTime - preparationStartMs}ms)`, _intlayer_config_colors.GREY_DARK)], { isVerbose: true });
60
- const dictionaries = await require_loadDictionaries_loadDictionaries.loadDictionaries(dictionariesWithStats.map((dictionary) => dictionary.path), configuration);
60
+ const contentDeclarationPaths = dictionariesWithStats.map((dictionary) => dictionary.path);
61
+ const dictionaries = await require_loadDictionaries_loadDictionaries.loadDictionaries(contentDeclarationPaths, configuration);
61
62
  const dictionariesLoadedTime = Date.now();
62
63
  appLogger(["Content loaded", (0, _intlayer_config_logger.colorize)([dictionaries.remoteDictionaries.length + dictionaries.pluginDictionaries.length > 0 ? [
63
64
  `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,
@@ -76,7 +77,8 @@ const prepareIntlayer = async (configuration, options) => {
76
77
  env
77
78
  });
78
79
  await require_buildIntlayerDictionary_writeRemoteDictionary.writeRemoteDictionary(dictionaries.remoteDictionaries, configuration);
79
- await require_createType_createType.createTypes(Object.values(dictionariesOutput?.mergedDictionaries ?? {}).map((dictionary) => dictionary.dictionary), configuration);
80
+ const dictionariesToBuild = Object.values(dictionariesOutput?.mergedDictionaries ?? {}).map((dictionary) => dictionary.dictionary);
81
+ await require_createType_createType.createTypes(dictionariesToBuild, configuration);
80
82
  await require_createDictionaryEntryPoint_createDictionaryEntryPoint.createDictionaryEntryPoint(configuration, { formats: options?.format });
81
83
  const dictionariesBuiltTime = Date.now();
82
84
  appLogger(["Dictionaries built", (0, _intlayer_config_logger.colorize)(`(${dictionariesBuiltTime - preparationStartMs}ms)`, _intlayer_config_colors.GREY_DARK)]);
@@ -1 +1 @@
1
- {"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","isCachedConfigurationUpToDate","listDictionariesWithStats","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { cacheDisk } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary';\nimport { cleanOutputDir } from './cleanOutputDir';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { listDictionariesWithStats } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport {\n isCachedConfigurationUpToDate,\n writeConfiguration,\n} from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\n env?: 'prod' | 'dev';\n format?: ('cjs' | 'esm')[];\n forceRun?: boolean;\n cacheTimeoutMs?: number;\n onIsCached?: () => void | Promise<void>;\n};\n\nconst DEFAULT_PREPARE_INTLAYER_OPTIONS = {\n clean: false,\n env: 'dev',\n format: ['cjs', 'esm'],\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n} satisfies PrepareIntlayerOptions;\n\nexport const prepareIntlayer = async (\n configuration: IntlayerConfig,\n options?: PrepareIntlayerOptions\n) => {\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n // Clean output dir if the intlayer version has changed\n const versionCache = cacheDisk(configuration, ['intlayer-version']);\n const intlayerCacheVersion = await versionCache.get();\n const isCorrectVersion = Boolean(\n intlayerCacheVersion === undefined ||\n intlayerCacheVersion === packageJson.version\n );\n\n const isConfigSimilar = await isCachedConfigurationUpToDate(configuration);\n\n // Check if any dictionary has been changed to force a new rebuild\n const dictionariesWithStats = await listDictionariesWithStats(configuration);\n let isDictionaryChanged = false;\n try {\n // Try catch as sentinel file may not exist yet\n const sentinelStats = await stat(sentinelPath);\n isDictionaryChanged = dictionariesWithStats.some(\n (dictionary) =>\n dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime()\n );\n } catch {}\n\n const resolvedPlugins = await Promise.all(configuration.plugins ?? []);\n const hasPluginLoadDictionaries = resolvedPlugins.some((plugin) =>\n Boolean(plugin.loadDictionaries)\n ); // Disable cache if any plugin because it can have custom behavior\n\n const { clean, format, forceRun, onIsCached, cacheTimeoutMs, env } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun:\n !isCorrectVersion ||\n !isConfigSimilar ||\n isDictionaryChanged ||\n hasPluginLoadDictionaries,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async ({ renewLock }) => {\n // comment because of issue with next and webpack\n // await checkVersionsConsistency(configuration);\n\n // Re-read the cached version now that the lock is held: another process\n // may have upgraded the output directory while this call was queued, in\n // which case cleaning it would throw away a build that just completed.\n const isCorrectVersionUnderLock =\n (await versionCache.get()) === packageJson.version;\n\n if (clean || !isCorrectVersionUnderLock) {\n await cleanOutputDir(configuration);\n // `cleanOutputDir` wipes the cache directory the sentinel lives in.\n // Re-create it immediately, otherwise a concurrent process (e.g. the\n // `intlayer watch` CLI next to a dev server) sees no lock, starts its\n // own run, and cleans the output directory while this one writes.\n await renewLock();\n }\n\n await versionCache.set(packageJson.version);\n\n const preparationStartMs = Date.now();\n\n appLogger([\n 'Preparing Intlayer',\n colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK),\n ]);\n\n await writeConfiguration(configuration);\n\n const configurationWrittenTime = Date.now();\n\n appLogger(\n [\n 'Configuration written',\n colorize(\n `(${configurationWrittenTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n const contentDeclarationPaths = dictionariesWithStats.map(\n (dictionary) => dictionary.path\n );\n\n const dictionaries = await loadDictionaries(\n contentDeclarationPaths,\n configuration\n );\n\n const dictionariesLoadedTime = Date.now();\n\n appLogger(\n [\n 'Content loaded',\n colorize(\n [\n dictionaries.remoteDictionaries.length +\n dictionaries.pluginDictionaries.length >\n 0\n ? [\n `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,\n dictionaries.localDictionaries.length > 0\n ? ` - Local: ${dictionaries.time.localDictionaries}ms`\n : '',\n dictionaries.remoteDictionaries.length > 0\n ? ` - Remote: ${dictionaries.time.remoteDictionaries}ms`\n : '',\n dictionaries.pluginDictionaries.length > 0\n ? ` - Plugin: ${dictionaries.time.pluginDictionaries}ms`\n : '',\n `)`,\n ].join('')\n : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`,\n ].join(''),\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Build local dictionaries\n const dictionariesOutput = await buildDictionary(\n [\n ...dictionaries.localDictionaries,\n ...dictionaries.remoteDictionaries,\n ...dictionaries.pluginDictionaries,\n ],\n configuration,\n { formats: format, importOtherDictionaries: false, env }\n );\n\n // Write remote dictionaries\n // Used as cache for next fetch\n await writeRemoteDictionary(\n dictionaries.remoteDictionaries,\n configuration\n );\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, configuration);\n\n await createDictionaryEntryPoint(configuration, {\n formats: options?.format,\n });\n\n const dictionariesBuiltTime = Date.now();\n\n appLogger([\n 'Dictionaries built',\n colorize(\n `(${dictionariesBuiltTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ]);\n\n await createModuleAugmentation(configuration);\n\n const moduleAugmentationBuiltTime = Date.now();\n\n appLogger(\n [\n 'Module augmentation built',\n colorize(\n `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Plugin transformation\n // Allow plugins to post-process the final build output (e.g., write back ICU JSON)\n for await (const plugin of configuration.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n try {\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\n });\n } catch (error) {\n // A failing write-back (e.g. transient network error on a remote\n // target) must not invalidate the dictionaries already built.\n appLogger(\n [\n `Plugin ${plugin.name} afterBuild failed:`,\n (error as Error).message,\n ],\n { level: 'error' }\n );\n }\n }\n\n const preparationElapsedMs = Date.now() - preparationStartMs;\n appLogger(\n [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)],\n {\n level: 'info',\n isVerbose: true,\n }\n );\n },\n {\n forceRun,\n onIsCached,\n cacheTimeoutMs,\n }\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"prepareIntlayer.cjs","names":["getAppLogger","join","cacheDisk","packageJson","isCachedConfigurationUpToDate","listDictionariesWithStats","stat","runOnce","cleanOutputDir","colorize","ANSIColors","writeConfiguration","loadDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { cacheDisk } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary';\nimport { cleanOutputDir } from './cleanOutputDir';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { listDictionariesWithStats } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport {\n isCachedConfigurationUpToDate,\n writeConfiguration,\n} from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\n env?: 'prod' | 'dev';\n format?: ('cjs' | 'esm')[];\n forceRun?: boolean;\n cacheTimeoutMs?: number;\n onIsCached?: () => void | Promise<void>;\n};\n\nconst DEFAULT_PREPARE_INTLAYER_OPTIONS = {\n clean: false,\n env: 'dev',\n format: ['cjs', 'esm'],\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n} satisfies PrepareIntlayerOptions;\n\nexport const prepareIntlayer = async (\n configuration: IntlayerConfig,\n options?: PrepareIntlayerOptions\n) => {\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n // Clean output dir if the intlayer version has changed\n const versionCache = cacheDisk(configuration, ['intlayer-version']);\n const intlayerCacheVersion = await versionCache.get();\n const isCorrectVersion = Boolean(\n intlayerCacheVersion === undefined ||\n intlayerCacheVersion === packageJson.version\n );\n\n const isConfigSimilar = await isCachedConfigurationUpToDate(configuration);\n\n // Check if any dictionary has been changed to force a new rebuild\n const dictionariesWithStats = await listDictionariesWithStats(configuration);\n let isDictionaryChanged = false;\n try {\n // Try catch as sentinel file may not exist yet\n const sentinelStats = await stat(sentinelPath);\n isDictionaryChanged = dictionariesWithStats.some(\n (dictionary) =>\n dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime()\n );\n } catch {}\n\n const resolvedPlugins = await Promise.all(configuration.plugins ?? []);\n const hasPluginLoadDictionaries = resolvedPlugins.some((plugin) =>\n Boolean(plugin.loadDictionaries)\n ); // Disable cache if any plugin because it can have custom behavior\n\n const { clean, format, forceRun, onIsCached, cacheTimeoutMs, env } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun:\n !isCorrectVersion ||\n !isConfigSimilar ||\n isDictionaryChanged ||\n hasPluginLoadDictionaries,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async ({ renewLock }) => {\n // comment because of issue with next and webpack\n // await checkVersionsConsistency(configuration);\n\n // Re-read the cached version now that the lock is held: another process\n // may have upgraded the output directory while this call was queued, in\n // which case cleaning it would throw away a build that just completed.\n const isCorrectVersionUnderLock =\n (await versionCache.get()) === packageJson.version;\n\n if (clean || !isCorrectVersionUnderLock) {\n await cleanOutputDir(configuration);\n // `cleanOutputDir` wipes the cache directory the sentinel lives in.\n // Re-create it immediately, otherwise a concurrent process (e.g. the\n // `intlayer watch` CLI next to a dev server) sees no lock, starts its\n // own run, and cleans the output directory while this one writes.\n await renewLock();\n }\n\n await versionCache.set(packageJson.version);\n\n const preparationStartMs = Date.now();\n\n appLogger([\n 'Preparing Intlayer',\n colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK),\n ]);\n\n await writeConfiguration(configuration);\n\n const configurationWrittenTime = Date.now();\n\n appLogger(\n [\n 'Configuration written',\n colorize(\n `(${configurationWrittenTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n const contentDeclarationPaths = dictionariesWithStats.map(\n (dictionary) => dictionary.path\n );\n\n const dictionaries = await loadDictionaries(\n contentDeclarationPaths,\n configuration\n );\n\n const dictionariesLoadedTime = Date.now();\n\n appLogger(\n [\n 'Content loaded',\n colorize(\n [\n dictionaries.remoteDictionaries.length +\n dictionaries.pluginDictionaries.length >\n 0\n ? [\n `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,\n dictionaries.localDictionaries.length > 0\n ? ` - Local: ${dictionaries.time.localDictionaries}ms`\n : '',\n dictionaries.remoteDictionaries.length > 0\n ? ` - Remote: ${dictionaries.time.remoteDictionaries}ms`\n : '',\n dictionaries.pluginDictionaries.length > 0\n ? ` - Plugin: ${dictionaries.time.pluginDictionaries}ms`\n : '',\n `)`,\n ].join('')\n : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`,\n ].join(''),\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Build local dictionaries\n const dictionariesOutput = await buildDictionary(\n [\n ...dictionaries.localDictionaries,\n ...dictionaries.remoteDictionaries,\n ...dictionaries.pluginDictionaries,\n ],\n configuration,\n { formats: format, importOtherDictionaries: false, env }\n );\n\n // Write remote dictionaries\n // Used as cache for next fetch\n await writeRemoteDictionary(\n dictionaries.remoteDictionaries,\n configuration\n );\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, configuration);\n\n await createDictionaryEntryPoint(configuration, {\n formats: options?.format,\n });\n\n const dictionariesBuiltTime = Date.now();\n\n appLogger([\n 'Dictionaries built',\n colorize(\n `(${dictionariesBuiltTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ]);\n\n await createModuleAugmentation(configuration);\n\n const moduleAugmentationBuiltTime = Date.now();\n\n appLogger(\n [\n 'Module augmentation built',\n colorize(\n `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Plugin transformation\n // Allow plugins to post-process the final build output (e.g., write back ICU JSON)\n for await (const plugin of configuration.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n try {\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\n });\n } catch (error) {\n // A failing write-back (e.g. transient network error on a remote\n // target) must not invalidate the dictionaries already built.\n appLogger(\n [\n `Plugin ${plugin.name} afterBuild failed:`,\n (error as Error).message,\n ],\n { level: 'error' }\n );\n }\n }\n\n const preparationElapsedMs = Date.now() - preparationStartMs;\n appLogger(\n [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)],\n {\n level: 'info',\n isVerbose: true,\n }\n );\n },\n {\n forceRun,\n onIsCached,\n cacheTimeoutMs,\n }\n );\n};\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/reduceDictionaryContent/applyMask.ts
4
3
  const applyMask = (full, mask) => {
5
4
  if (mask === true) return full;
@@ -1 +1 @@
1
- {"version":3,"file":"applyMask.cjs","names":[],"sources":["../../../src/reduceDictionaryContent/applyMask.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\n\nexport const applyMask = (full: Dictionary, mask: any): Dictionary => {\n // the mask \"true\" → we don't filter\n if (mask === true) {\n return full;\n }\n\n // arrays\n if (Array.isArray(mask) && Array.isArray(full)) {\n return mask.map((m, i) => applyMask(full[i], m)) as any;\n }\n\n // handle node with nodeType property\n if (full && typeof full === 'object' && 'nodeType' in full) {\n if (mask && typeof mask === 'object') {\n return full; // Keep the full object with nodeType intact\n }\n return full;\n }\n\n // generic object\n if (mask && typeof mask === 'object' && full && typeof full === 'object') {\n const out: any = {};\n const maskEntries = Object.entries(mask);\n const allChildrenAreArrays = maskEntries.every(([, value]) =>\n Array.isArray(value)\n );\n\n for (const [k, m] of maskEntries) {\n const fullValue = (full as any)[k];\n\n // If this child is an array, decide preservation rules.\n // - Preserve when all children at this level are arrays in the mask\n // - Also preserve when the array is an array of translation nodes\n if (Array.isArray(m) && Array.isArray(fullValue)) {\n const isTranslationNode = (val: unknown): boolean =>\n !!val && typeof val === 'object' && 'nodeType' in (val as any);\n const isArrayOfTranslationNodes = fullValue.every((item: any) =>\n isTranslationNode(item)\n );\n\n if (!allChildrenAreArrays && !isArrayOfTranslationNodes) {\n continue; // skip incidental arrays when mixed with non-arrays\n }\n }\n\n out[k] = applyMask(fullValue, m);\n }\n return out;\n }\n\n // unexpected case: we return the original value\n return full;\n};\n"],"mappings":";;;AAEA,MAAa,aAAa,MAAkB,SAA0B;CAEpE,IAAI,SAAS,MACX,OAAO;CAIT,IAAI,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,GAC3C,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC;CAIjD,IAAI,QAAQ,OAAO,SAAS,YAAY,cAAc,MAAM;EAC1D,IAAI,QAAQ,OAAO,SAAS,UAC1B,OAAO;EAET,OAAO;CACT;CAGA,IAAI,QAAQ,OAAO,SAAS,YAAY,QAAQ,OAAO,SAAS,UAAU;EACxE,MAAM,MAAW,CAAC;EAClB,MAAM,cAAc,OAAO,QAAQ,IAAI;EACvC,MAAM,uBAAuB,YAAY,OAAO,GAAG,WACjD,MAAM,QAAQ,KAAK,CACrB;EAEA,KAAK,MAAM,CAAC,GAAG,MAAM,aAAa;GAChC,MAAM,YAAa,KAAa;GAKhC,IAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,SAAS,GAAG;IAChD,MAAM,qBAAqB,QACzB,CAAC,CAAC,OAAO,OAAO,QAAQ,YAAY,cAAe;IACrD,MAAM,4BAA4B,UAAU,OAAO,SACjD,kBAAkB,IAAI,CACxB;IAEA,IAAI,CAAC,wBAAwB,CAAC,2BAC5B;GAEJ;GAEA,IAAI,KAAK,UAAU,WAAW,CAAC;EACjC;EACA,OAAO;CACT;CAGA,OAAO;AACT"}
1
+ {"version":3,"file":"applyMask.cjs","names":[],"sources":["../../../src/reduceDictionaryContent/applyMask.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\n\nexport const applyMask = (full: Dictionary, mask: any): Dictionary => {\n // the mask \"true\" → we don't filter\n if (mask === true) {\n return full;\n }\n\n // arrays\n if (Array.isArray(mask) && Array.isArray(full)) {\n return mask.map((m, i) => applyMask(full[i], m)) as any;\n }\n\n // handle node with nodeType property\n if (full && typeof full === 'object' && 'nodeType' in full) {\n if (mask && typeof mask === 'object') {\n return full; // Keep the full object with nodeType intact\n }\n return full;\n }\n\n // generic object\n if (mask && typeof mask === 'object' && full && typeof full === 'object') {\n const out: any = {};\n const maskEntries = Object.entries(mask);\n const allChildrenAreArrays = maskEntries.every(([, value]) =>\n Array.isArray(value)\n );\n\n for (const [k, m] of maskEntries) {\n const fullValue = (full as any)[k];\n\n // If this child is an array, decide preservation rules.\n // - Preserve when all children at this level are arrays in the mask\n // - Also preserve when the array is an array of translation nodes\n if (Array.isArray(m) && Array.isArray(fullValue)) {\n const isTranslationNode = (val: unknown): boolean =>\n !!val && typeof val === 'object' && 'nodeType' in (val as any);\n const isArrayOfTranslationNodes = fullValue.every((item: any) =>\n isTranslationNode(item)\n );\n\n if (!allChildrenAreArrays && !isArrayOfTranslationNodes) {\n continue; // skip incidental arrays when mixed with non-arrays\n }\n }\n\n out[k] = applyMask(fullValue, m);\n }\n return out;\n }\n\n // unexpected case: we return the original value\n return full;\n};\n"],"mappings":";;AAEA,MAAa,aAAa,MAAkB,SAA0B;CAEpE,IAAI,SAAS,MACX,OAAO;CAIT,IAAI,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,GAC3C,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC;CAIjD,IAAI,QAAQ,OAAO,SAAS,YAAY,cAAc,MAAM;EAC1D,IAAI,QAAQ,OAAO,SAAS,UAC1B,OAAO;EAET,OAAO;CACT;CAGA,IAAI,QAAQ,OAAO,SAAS,YAAY,QAAQ,OAAO,SAAS,UAAU;EACxE,MAAM,MAAW,CAAC;EAClB,MAAM,cAAc,OAAO,QAAQ,IAAI;EACvC,MAAM,uBAAuB,YAAY,OAAO,GAAG,WACjD,MAAM,QAAQ,KAAK,CACrB;EAEA,KAAK,MAAM,CAAC,GAAG,MAAM,aAAa;GAChC,MAAM,YAAa,KAAa;GAKhC,IAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,SAAS,GAAG;IAChD,MAAM,qBAAqB,QACzB,CAAC,CAAC,OAAO,OAAO,QAAQ,YAAY,cAAe;IACrD,MAAM,4BAA4B,UAAU,OAAO,SACjD,kBAAkB,IAAI,CACxB;IAEA,IAAI,CAAC,wBAAwB,CAAC,2BAC5B;GAEJ;GAEA,IAAI,KAAK,UAAU,WAAW,CAAC;EACjC;EACA,OAAO;CACT;CAGA,OAAO;AACT"}
@@ -4,7 +4,8 @@ let _intlayer_core_plugins = require("@intlayer/core/plugins");
4
4
 
5
5
  //#region src/reduceDictionaryContent/reduceDictionaryContent.ts
6
6
  const reduceDictionaryContent = (fullDictionary, partialDictionary) => {
7
- return require_reduceDictionaryContent_applyMask.applyMask(fullDictionary, (0, _intlayer_core_plugins.getMaskContent)(partialDictionary));
7
+ const mask = (0, _intlayer_core_plugins.getMaskContent)(partialDictionary);
8
+ return require_reduceDictionaryContent_applyMask.applyMask(fullDictionary, mask);
8
9
  };
9
10
 
10
11
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"reduceDictionaryContent.cjs","names":["applyMask"],"sources":["../../../src/reduceDictionaryContent/reduceDictionaryContent.ts"],"sourcesContent":["import { getMaskContent } from '@intlayer/core/plugins';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { applyMask } from './applyMask';\n\nexport const reduceDictionaryContent = (\n fullDictionary: Dictionary,\n partialDictionary: Dictionary\n) => {\n const mask = getMaskContent(partialDictionary);\n const result = applyMask(fullDictionary, mask);\n\n return result;\n};\n"],"mappings":";;;;;AAIA,MAAa,2BACX,gBACA,sBACG;CAIH,OAFeA,oDAAU,2DADG,iBACgB,CAEhC;AACd"}
1
+ {"version":3,"file":"reduceDictionaryContent.cjs","names":["getMaskContent","applyMask"],"sources":["../../../src/reduceDictionaryContent/reduceDictionaryContent.ts"],"sourcesContent":["import { getMaskContent } from '@intlayer/core/plugins';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { applyMask } from './applyMask';\n\nexport const reduceDictionaryContent = (\n fullDictionary: Dictionary,\n partialDictionary: Dictionary\n) => {\n const mask = getMaskContent(partialDictionary);\n const result = applyMask(fullDictionary, mask);\n\n return result;\n};\n"],"mappings":";;;;;AAIA,MAAa,2BACX,gBACA,sBACG;CACH,MAAM,WAAOA,uCAAe,iBAAiB;CAG7C,OAFeC,oDAAU,gBAAgB,IAE7B;AACd"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/scan/calculateScore.ts
4
3
  /**
5
4
  * Resolve how many points an event contributes based on its status.
@@ -1 +1 @@
1
- {"version":3,"file":"calculateScore.cjs","names":[],"sources":["../../../src/scan/calculateScore.ts"],"sourcesContent":["/**\n * Mutualized SEO/i18n scoring logic.\n *\n * This module is the single source of truth for turning audit/scan events into\n * a weighted score. It is consumed both by the hosted backend SEO audit\n * (`apps/backend`) and by the `intlayer scan` CLI command, so it must stay free\n * of any server-only dependency (no Fastify, no Cheerio, no logger coupling).\n */\n\n/** Accumulated score across all checks that ran. */\nexport type Score = {\n /** Sum of points obtained (success = full, warning = half, error = none). */\n score: number;\n /** Maximum achievable points for the checks that ran. */\n totalScore: number;\n};\n\n/**\n * Minimal shape of an event needed to contribute to the score.\n *\n * The `type` is the check identifier. URL-scoped checks are suffixed with the\n * URL using a backslash separator (e.g. `url_htmlLang\\https://example.com`), so\n * only the part before the first backslash is used to look up the weight.\n */\nexport type ScorableEvent = {\n type?: string;\n status?: string;\n};\n\n/**\n * Resolve how many points an event contributes based on its status.\n * - `warning` → half of the weight\n * - `error` → none\n * - anything else (`success`, `started`, `done`, …) → full weight\n */\nconst scoreCheck = (score: number, event: ScorableEvent): number => {\n if (event.status === 'warning') return score / 2;\n if (event.status === 'error') return 0;\n return score;\n};\n\n/** Weight (in points) of every scorable check. */\nexport const scoreRecord = {\n robots_robotsPresent: 10,\n robots_noLocalizedUrlsForgotten: 8,\n sitemap_sitemapPresent: 10,\n sitemap_noLocalizedUrlsForgotten: 9,\n sitemap_hasAlternates: 8,\n sitemap_hasXDefault: 7,\n url_htmlLang: 9,\n url_htmlDir: 3,\n url_hasCanonical: 10,\n url_hreflang: 9,\n url_hasLocalizedLinks: 8,\n url_hasXDefault: 7,\n url_allAnchorsLocalized: 6,\n url_currentLocale: 3,\n url_unusedBundleContent: 8,\n} as const;\n\n/** Identifier of a scorable check (without the URL suffix). */\nexport type ScoreCheckType = keyof typeof scoreRecord;\n\n/**\n * Apply a single event to the running score, returning a new {@link Score}.\n * Unknown check types are ignored so the function is safe to call on every\n * emitted event.\n *\n * @param score - The current accumulated score.\n * @param event - The event to fold into the score.\n * @returns A new score with the event applied.\n */\nexport const mutateScore = (score: Score, event: ScorableEvent): Score => {\n const newScore: Score = { ...score };\n\n const typeWithoutUrl = event.type?.split('\\\\')[0];\n\n if (!typeWithoutUrl) {\n return newScore;\n }\n\n const scoreValue = scoreRecord[typeWithoutUrl as ScoreCheckType];\n\n if (typeof scoreValue === 'number') {\n newScore.score += scoreCheck(scoreValue, event);\n newScore.totalScore += scoreValue;\n }\n\n return newScore;\n};\n\n/**\n * Convert a raw {@link Score} into a 0–100 percentage.\n *\n * @param score - The accumulated score.\n * @returns The rounded percentage, or 0 when no check ran.\n */\nexport const toScorePercent = (score: Score): number =>\n Math.round(score.totalScore > 0 ? (score.score / score.totalScore) * 100 : 0);\n"],"mappings":";;;;;;;;;AAmCA,MAAM,cAAc,OAAe,UAAiC;CAClE,IAAI,MAAM,WAAW,WAAW,OAAO,QAAQ;CAC/C,IAAI,MAAM,WAAW,SAAS,OAAO;CACrC,OAAO;AACT;;AAGA,MAAa,cAAc;CACzB,sBAAsB;CACtB,iCAAiC;CACjC,wBAAwB;CACxB,kCAAkC;CAClC,uBAAuB;CACvB,qBAAqB;CACrB,cAAc;CACd,aAAa;CACb,kBAAkB;CAClB,cAAc;CACd,uBAAuB;CACvB,iBAAiB;CACjB,yBAAyB;CACzB,mBAAmB;CACnB,yBAAyB;AAC3B;;;;;;;;;;AAcA,MAAa,eAAe,OAAc,UAAgC;CACxE,MAAM,WAAkB,EAAE,GAAG,MAAM;CAEnC,MAAM,iBAAiB,MAAM,MAAM,MAAM,IAAI,CAAC,CAAC;CAE/C,IAAI,CAAC,gBACH,OAAO;CAGT,MAAM,aAAa,YAAY;CAE/B,IAAI,OAAO,eAAe,UAAU;EAClC,SAAS,SAAS,WAAW,YAAY,KAAK;EAC9C,SAAS,cAAc;CACzB;CAEA,OAAO;AACT;;;;;;;AAQA,MAAa,kBAAkB,UAC7B,KAAK,MAAM,MAAM,aAAa,IAAK,MAAM,QAAQ,MAAM,aAAc,MAAM,CAAC"}
1
+ {"version":3,"file":"calculateScore.cjs","names":[],"sources":["../../../src/scan/calculateScore.ts"],"sourcesContent":["/**\n * Mutualized SEO/i18n scoring logic.\n *\n * This module is the single source of truth for turning audit/scan events into\n * a weighted score. It is consumed both by the hosted backend SEO audit\n * (`apps/backend`) and by the `intlayer scan` CLI command, so it must stay free\n * of any server-only dependency (no Fastify, no Cheerio, no logger coupling).\n */\n\n/** Accumulated score across all checks that ran. */\nexport type Score = {\n /** Sum of points obtained (success = full, warning = half, error = none). */\n score: number;\n /** Maximum achievable points for the checks that ran. */\n totalScore: number;\n};\n\n/**\n * Minimal shape of an event needed to contribute to the score.\n *\n * The `type` is the check identifier. URL-scoped checks are suffixed with the\n * URL using a backslash separator (e.g. `url_htmlLang\\https://example.com`), so\n * only the part before the first backslash is used to look up the weight.\n */\nexport type ScorableEvent = {\n type?: string;\n status?: string;\n};\n\n/**\n * Resolve how many points an event contributes based on its status.\n * - `warning` → half of the weight\n * - `error` → none\n * - anything else (`success`, `started`, `done`, …) → full weight\n */\nconst scoreCheck = (score: number, event: ScorableEvent): number => {\n if (event.status === 'warning') return score / 2;\n if (event.status === 'error') return 0;\n return score;\n};\n\n/** Weight (in points) of every scorable check. */\nexport const scoreRecord = {\n robots_robotsPresent: 10,\n robots_noLocalizedUrlsForgotten: 8,\n sitemap_sitemapPresent: 10,\n sitemap_noLocalizedUrlsForgotten: 9,\n sitemap_hasAlternates: 8,\n sitemap_hasXDefault: 7,\n url_htmlLang: 9,\n url_htmlDir: 3,\n url_hasCanonical: 10,\n url_hreflang: 9,\n url_hasLocalizedLinks: 8,\n url_hasXDefault: 7,\n url_allAnchorsLocalized: 6,\n url_currentLocale: 3,\n url_unusedBundleContent: 8,\n} as const;\n\n/** Identifier of a scorable check (without the URL suffix). */\nexport type ScoreCheckType = keyof typeof scoreRecord;\n\n/**\n * Apply a single event to the running score, returning a new {@link Score}.\n * Unknown check types are ignored so the function is safe to call on every\n * emitted event.\n *\n * @param score - The current accumulated score.\n * @param event - The event to fold into the score.\n * @returns A new score with the event applied.\n */\nexport const mutateScore = (score: Score, event: ScorableEvent): Score => {\n const newScore: Score = { ...score };\n\n const typeWithoutUrl = event.type?.split('\\\\')[0];\n\n if (!typeWithoutUrl) {\n return newScore;\n }\n\n const scoreValue = scoreRecord[typeWithoutUrl as ScoreCheckType];\n\n if (typeof scoreValue === 'number') {\n newScore.score += scoreCheck(scoreValue, event);\n newScore.totalScore += scoreValue;\n }\n\n return newScore;\n};\n\n/**\n * Convert a raw {@link Score} into a 0–100 percentage.\n *\n * @param score - The accumulated score.\n * @returns The rounded percentage, or 0 when no check ran.\n */\nexport const toScorePercent = (score: Score): number =>\n Math.round(score.totalScore > 0 ? (score.score / score.totalScore) * 100 : 0);\n"],"mappings":";;;;;;;;AAmCA,MAAM,cAAc,OAAe,UAAiC;CAClE,IAAI,MAAM,WAAW,WAAW,OAAO,QAAQ;CAC/C,IAAI,MAAM,WAAW,SAAS,OAAO;CACrC,OAAO;AACT;;AAGA,MAAa,cAAc;CACzB,sBAAsB;CACtB,iCAAiC;CACjC,wBAAwB;CACxB,kCAAkC;CAClC,uBAAuB;CACvB,qBAAqB;CACrB,cAAc;CACd,aAAa;CACb,kBAAkB;CAClB,cAAc;CACd,uBAAuB;CACvB,iBAAiB;CACjB,yBAAyB;CACzB,mBAAmB;CACnB,yBAAyB;AAC3B;;;;;;;;;;AAcA,MAAa,eAAe,OAAc,UAAgC;CACxE,MAAM,WAAkB,EAAE,GAAG,MAAM;CAEnC,MAAM,iBAAiB,MAAM,MAAM,MAAM,IAAI,CAAC,CAAC;CAE/C,IAAI,CAAC,gBACH,OAAO;CAGT,MAAM,aAAa,YAAY;CAE/B,IAAI,OAAO,eAAe,UAAU;EAClC,SAAS,SAAS,WAAW,YAAY,KAAK;EAC9C,SAAS,cAAc;CACzB;CAEA,OAAO;AACT;;;;;;;AAQA,MAAa,kBAAkB,UAC7B,KAAK,MAAM,MAAM,aAAa,IAAK,MAAM,QAAQ,MAAM,aAAc,MAAM,CAAC"}
@@ -6,7 +6,7 @@ let _intlayer_types_allLocales = require("@intlayer/types/allLocales");
6
6
  //#region src/scan/checks.ts
7
7
  /** Format a byte count as a human-readable size. */
8
8
  const formatSize = (bytes) => {
9
- if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
9
+ if (bytes >= 1048576) return `${(bytes / 1048576).toFixed(2)} MB`;
10
10
  if (bytes >= 1024) return `${(bytes / 1024).toFixed(2)} KB`;
11
11
  return `${bytes} B`;
12
12
  };
@@ -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":";;;;;;;AAgBA,MAAa,cAAc,UAA0B;CACnD,IAAI,SAAS,OAAO,MAAM,OAAO,IAAI,SAAS,OAAO,MAAK,CAAE,QAAQ,CAAC,EAAE;CACvE,IAAI,SAAS,MAAM,OAAO,IAAI,QAAQ,KAAI,CAAE,QAAQ,CAAC,EAAE;CACvD,OAAO,GAAG,MAAM;AAClB;;;;;AAMA,MAAa,uBACX,MACA,WACA,WACoC;CACpC,MAAM,UAAUA,uCAAgB,IAAI;CACpC,MAAM,SAASC,sCAAe,IAAI;CAElC,OAAO,KAAK;EACV,MAAM,iBAAiB;EACvB,QAAQ,UAAU,YAAY;EAC9B,SAAS;GACP,SAAS;GACT,OAAO,UAAU,SAAY;EAC/B;CACF,CAAC;CAED,OAAO,KAAK;EACV,MAAM,sBAAsB;EAC5B,QAAQ,UAAU,YAAY;EAC9B,SAAS;GACP,SAAS;GACT,SAAS,UAAU,SAAY;EACjC;CACF,CAAC;CAED,OAAO,KAAK;EACV,MAAM,gBAAgB;EACtB,QAAQ,SAAS,YAAY;EAC7B,SAAS;GACP,SAAS;GACT,SAAS,SAAS,SAAY;EAChC;CACF,CAAC;CAED,OAAO,EAAE,QAAQ;AACnB;;AAGA,MAAa,kBACX,MACA,WACA,WACS;CACT,MAAM,UAAUC,oCAAa,IAAI;CACjC,OAAO,KAAK;EACV,MAAM,qBAAqB;EAC3B,QAAQ,UAAU,YAAY;EAC9B,SAAS,EAAE,SAAS,UAAU,SAAY,yBAAyB;CACrE,CAAC;AACH;;;;;AAMA,MAAa,4BACX,MACA,WACA,YACA,WACS;CACT,MAAM,UAAUF,uCAAgB,IAAI;CACpC,IAAI,SAAS,WAAW,IAAI,OAAO;CAEnC,MAAM,YAAYG,wCAAiB,IAAI;CACvC,KAAK,MAAM,EAAE,cAAc,WACzB,IAAI,aAAa,aAAa,WAAW,IAAI,QAAQ;CAGvD,MAAM,cAAc,UAAU,MAAM,MAAM,EAAE,aAAa,WAAW;CAEpE,OAAO,KAAK;EACV,MAAM,iBAAiB;EACvB,QAAQ,UAAU,SAAS,IAAI,YAAY;EAC3C,SAAS;GACP,SAAS,UAAU,SAAS,IAAI,YAAY;GAC5C,SAAS,UAAU,WAAW,IAAI,2BAA2B;EAC/D;CACF,CAAC;CAED,OAAO,KAAK;EACV,MAAM,oBAAoB;EAC1B,QAAQ,cAAc,YAAY;EAClC,SAAS,EACP,OAAO,cAAc,SAAY,kCACnC;CACF,CAAC;AACH;AAEA,MAAM,iBAAiB,SACrB,KAAK,WAAW,MAAM,IAAI,KAAK,MAAM,CAAC,IAAI;AAE5C,MAAM,eAAe,OAAO,OAAOC,sCAAW;;;;;;AAO9C,MAAa,qBACX,SACA,QACA,WACA,WACS;CACT,MAAM,iBAAiB,cAAc,IAAI,IAAI,MAAM,CAAC,CAAC,QAAQ;CAE7D,IAAI,iBAAiB;CACrB,IAAI,qBAAqB;CACzB,MAAM,oBAA8B,CAAC;CAErC,KAAK,MAAM,EAAE,UAAU,SAAS;EAC9B,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,aAAa,GAChE;EAEF,IAAI;GACF,MAAM,MAAM,IAAI,IAAI,MAAM,MAAM;GAChC,IAAI,cAAc,IAAI,QAAQ,MAAM,gBAAgB;GAEpD;GACA,MAAM,OAAO,IAAI,SAAS,YAAY;GACtC,MAAM,WAAW,IAAI,SAAS,YAAY;GAE1C,MAAM,kBAAkB,aAAa,MAAM,WAAW;IACpD,MAAM,IAAI,OAAO,YAAY;IAC7B,OAAO,SAAS,IAAI,OAAO,KAAK,SAAS,IAAI,EAAE,EAAE;GACnD,CAAC;GACD,MAAM,uBAAuB,aAAa,MAAM,WAAW;IACzD,MAAM,IAAI,OAAO,YAAY;IAC7B,OAAO,SAAS,WAAW,GAAG,EAAE,EAAE,KAAK,SAAS,SAAS,IAAI,EAAE,EAAE;GACnE,CAAC;GAED,IAAI,mBAAmB,sBACrB;QAEA,kBAAkB,KAAK,IAAI;EAE/B,QAAQ,CAER;CACF;CAEA,MAAM,oBAAoB,iBAAiB;CAC3C,MAAM,sBACJ,uBAAuB,KAAK,mBAAmB;CAEjD,OAAO,KAAK;EACV,MAAM,0BAA0B;EAChC,QAAQ,oBAAoB,YAAY;EACxC,SAAS;GACP,SAAS,oBACL,GAAG,eAAe,gCAAgC,mBAAmB,mBACrE;GACJ,SAAS,oBAAoB,SAAY;EAC3C;CACF,CAAC;CAED,OAAO,KAAK;EACV,MAAM,4BAA4B;EAClC,QAAQ,sBAAsB,YAAY;EAC1C,SAAS,EACP,SAAS,sBACL,SACA;GACE,SAAS;GACT,OAAO;EACT,EACN;CACF,CAAC;AACH;;;;;AAMA,MAAa,sBACX,QACA,MACA,eACA,WACA,eACA,WACsC;CACtC,IAAI,CAAC,eAAe;EAClB,OAAO,KAAK;GACV,MAAM,4BAA4B;GAClC,QAAQ;GACR,SAAS,EACP,SAAS,0DACX;EACF,CAAC;EACD;CACF;CAEA,MAAM,WAAWC,uDACf,QACA,MACA,eACA,aACF;CAGA,MAAM,sBAAsB,SAAS,iBAAiB,QACnD,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,aAAa,GACzC,CACF;CAEA,MAAM,SACJ,wBAAwB,IACpB,YACA,uBAAuB,KACrB,YACA;CAER,OAAO,KAAK;EACV,MAAM,4BAA4B;EAClC;EACA,SAAS,GAAG,SAAS,SAAS;CAChC,CAAC;CAED,OAAO;AACT;;AAGA,MAAa,cAAc,OACzB,QACA,mBACA,WACA,WACkB;CAClB,IAAI,gBAAgB;CACpB,IAAI,2BAA2B;CAC/B,MAAM,SAAmB,CAAC;CAE1B,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,cAAc,EACnD,SAAS,EAAE,cAAc,UAAU,EACrC,CAAC;EAED,IAAI,SAAS,IAAI;GACf,gBAAgB;GAChB,MAAM,UAAU,MAAM,SAAS,KAAK;GAEpC,IAAI,WAAW,kBAAkB,OAAO,GAAG;IACzC,MAAM,kBAAkB,QACrB,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CACxC,QAAQ,SAAS,KAAK,WAAW,WAAW,CAAC,CAAC,CAC9C,KAAK,SAAS,KAAK,MAAM,CAAkB,CAAC,CAAC,KAAK,CAAC;IAEtD,KAAK,MAAM,UAAU,mBACnB,KAAK,MAAM,QAAQ,iBACjB,IAAI,SAAS,IAAI,YAAY,SAAS,IAAI,OAAO,IAAI;KACnD,2BAA2B;KAC3B,OAAO,KACL,gBAAgB,OAAO,yCAAyC,MAClE;IACF;GAGN;EACF;CACF,SAAS,OAAO;EACd,OAAO,KACL,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,iBAC1E;CACF;CAEA,OAAO,KAAK;EACV,MAAM;EACN,QAAQ,gBAAgB,YAAY;EACpC,SAAS;GACP,SAAS,gBAAgB,SAAY;GACrC,OAAO,OAAO,SAAS,IAAI,SAAS;EACtC;CACF,CAAC;CAED,IAAI,eACF,OAAO,KAAK;EACV,MAAM;EACN,QAAQ,2BAA2B,YAAY;EAC/C,SAAS,EAAE,OAAO,2BAA2B,SAAY,OAAO;CAClE,CAAC;AAEL;;AAGA,MAAa,eAAe,OAC1B,QACA,mBACA,WACA,WACkB;CAClB,IAAI,iBAAiB;CACrB,IAAI,cAAc;CAClB,IAAI,gBAAgB;CACpB,IAAI,2BAA2B;CAC/B,MAAM,SAAmB,CAAC;CAE1B,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,eAAe,EACpD,SAAS,EAAE,cAAc,UAAU,EACrC,CAAC;EAED,IAAI,SAAS,IAAI;GACf,iBAAiB;GACjB,MAAM,UAAU,MAAM,SAAS,KAAK;GAGpC,MAAM,aADkB,QAAQ,MAAM,4BAA4B,KAAK,CAAC,EACvC,CAAC,KAAK,MACrC,EAAE,QAAQ,qBAAqB,EAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,CACrD;GACA,gBAAgB,UAAU,SAAS;GACnC,cAAc,UAAU,SAAS,WAAW;GAE5C,IAAI,kBAAkB,OAAO,GAAG;IAC9B,MAAM,YAAY,QAAQ,MAAM,yBAAyB,KAAK,CAAC;IAC/D,MAAM,kCAAkB,IAAI,IAAY;IACxC,IAAI,sBAAsB;IAE1B,KAAK,MAAM,SAAS,WAAW;KAC7B,MAAM,+BAAe,IAAI,IAAY;KAErC,KAAK,MAAM,YAAY,MAAM,MAAM,4BAA4B,KAC7D,CAAC,GAAG;MACJ,MAAM,QAAQ,SACX,QAAQ,qBAAqB,EAAE,CAAC,CAChC,QAAQ,MAAM,EAAE;MACnB,IAAI,UAAU,aAAa;OACzB,aAAa,IAAI,KAAK;OACtB,gBAAgB,IAAI,KAAK;MAC3B;KACF;KAEA,MAAM,MAAM,MAAM,MAAM,yBAAyB,CAAC,GAAG,EAAE,EAAE,KAAK;KAC9D,IAAI,KACF,IAAI;MACF,MAAM,eAAe,IAAI,IAAI,GAAG,CAAC,CAAC,SAC/B,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CAAC;MACnB,IAAI,gBAAgB,kBAAkB,IAAI,YAAY,GAAG;OACvD,aAAa,IAAI,YAAY;OAC7B,gBAAgB,IAAI,YAAY;MAClC;KACF,QAAQ,CAER;KAGF,MAAM,UAAU,CAAC,GAAG,iBAAiB,CAAC,CAAC,QACpC,WAAW,CAAC,aAAa,IAAI,MAAM,CACtC;KACA,IAAI,QAAQ,SAAS,KAAK,QAAQ,SAAS,kBAAkB,MAC3D,sBAAsB;IAE1B;IAEA,MAAM,oBAAoB,CAAC,GAAG,iBAAiB,CAAC,CAAC,QAC9C,WAAW,CAAC,gBAAgB,IAAI,MAAM,CACzC;IACA,IAAI,uBAAuB,kBAAkB,SAAS,GAAG;KACvD,2BAA2B;KAC3B,IAAI,kBAAkB,SAAS,GAC7B,OAAO,KACL,kEAAkE,kBAAkB,KAAK,IAAI,GAC/F;IAEJ;GACF;EACF;CACF,SAAS,OAAO;EACd,OAAO,KACL,gCAAgC,iBAAiB,QAAQ,MAAM,UAAU,iBAC3E;CACF;CAEA,OAAO,KAAK;EACV,MAAM;EACN,QAAQ,iBAAiB,YAAY;EACrC,SAAS;GACP,SAAS,iBAAiB,SAAY;GACtC,OAAO,OAAO,SAAS,IAAI,SAAS;EACtC;CACF,CAAC;CAED,IAAI,gBAAgB;EAClB,OAAO,KAAK;GACV,MAAM;GACN,QAAQ,2BAA2B,YAAY;GAC/C,SAAS,EAAE,SAAS,2BAA2B,SAAY,OAAO;EACpE,CAAC;EAED,OAAO,KAAK;GACV,MAAM;GACN,QAAQ,cAAc,YAAY;GAClC,SAAS,EACP,SAAS,cAAc,SAAY,mCACrC;EACF,CAAC;EAED,OAAO,KAAK;GACV,MAAM;GACN,QAAQ,gBAAgB,YAAY;GACpC,SAAS,EACP,SAAS,gBACL,SACA,+CACN;EACF,CAAC;CACH;AACF"}
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,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/scan/parseHtml.ts
4
3
  /**
5
4
  * Tiny dependency-free HTML extraction helpers.
@@ -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 +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":["colorize","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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"}
@@ -37,7 +37,8 @@ const createFileAdapter = (options) => {
37
37
  const globPatternLocale = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext("**", locale));
38
38
  const maskPatternLocale = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext("{{__KEY__}}", locale));
39
39
  if (!globPatternLocale || !maskPatternLocale) continue;
40
- const files = await (0, fast_glob.default)(globPatternLocale.startsWith("./") ? globPatternLocale.slice(2) : globPatternLocale, { cwd: baseDir });
40
+ const normalizedGlobPattern = globPatternLocale.startsWith("./") ? globPatternLocale.slice(2) : globPatternLocale;
41
+ const files = await (0, fast_glob.default)(normalizedGlobPattern, { cwd: baseDir });
41
42
  const hasLocaleInMask = maskPatternLocale.includes("{{__LOCALE__}}");
42
43
  const hasKeyInMask = maskPatternLocale.includes("{{__KEY__}}");
43
44
  for (const file of files) {