@intlayer/engine 9.2.0 → 9.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/README.md +24 -24
  2. package/dist/assets/initConfig/templates/cjs.txt +1 -1
  3. package/dist/assets/initConfig/templates/mjs.txt +1 -1
  4. package/dist/assets/initConfig/templates/ts.txt +1 -1
  5. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  6. package/dist/cjs/_virtual/_utils_asset.cjs +2 -1
  7. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs +14 -2
  8. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  9. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +26 -5
  10. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
  11. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs +43 -6
  12. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
  13. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -1
  14. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
  15. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs +96 -0
  16. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -0
  17. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +4 -2
  18. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
  19. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
  20. package/dist/cjs/cleanOutputDir.cjs.map +1 -1
  21. package/dist/cjs/cleanRemovedContentDeclaration.cjs +7 -4
  22. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  23. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +5 -3
  24. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
  25. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
  26. package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
  27. package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
  28. package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
  29. package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
  30. package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
  31. package/dist/cjs/createType/createModuleAugmentation.cjs +2 -1
  32. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  33. package/dist/cjs/createType/createType.cjs.map +1 -1
  34. package/dist/cjs/detectFormatCommand.cjs.map +1 -1
  35. package/dist/cjs/docReview/alignBlocks.cjs +1 -1
  36. package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
  37. package/dist/cjs/docReview/computeSimilarity.cjs +0 -1
  38. package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
  39. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +0 -1
  40. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
  41. package/dist/cjs/docReview/normalizeBlock.cjs +0 -1
  42. package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
  43. package/dist/cjs/docReview/planActions.cjs +0 -1
  44. package/dist/cjs/docReview/planActions.cjs.map +1 -1
  45. package/dist/cjs/docReview/rebuildDocument.cjs +0 -1
  46. package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
  47. package/dist/cjs/docReview/reviewReport.cjs +2 -1
  48. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  49. package/dist/cjs/docReview/segmentDocument.cjs +0 -1
  50. package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
  51. package/dist/cjs/fetchDistantDictionaries.cjs +107 -13
  52. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  53. package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
  54. package/dist/cjs/formatDictionary.cjs.map +1 -1
  55. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
  56. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +4 -2
  57. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
  58. package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -2
  59. package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
  60. package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
  61. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +4 -2
  62. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
  63. package/dist/cjs/init/cms.cjs.map +1 -1
  64. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
  65. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +1 -3
  66. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  67. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +2 -1
  68. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
  69. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +0 -1
  70. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
  71. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
  72. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +3 -5
  73. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  74. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -1
  75. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
  76. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +18 -12
  77. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
  78. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +58 -15
  79. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  80. package/dist/cjs/init/index.cjs +66 -38
  81. package/dist/cjs/init/index.cjs.map +1 -1
  82. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  83. package/dist/cjs/init/utils/fileSystem.cjs +3 -1
  84. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  85. package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
  86. package/dist/cjs/init/utils/jsonParser.cjs +0 -1
  87. package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
  88. package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
  89. package/dist/cjs/init/utils/packageManager.cjs +4 -2
  90. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  91. package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
  92. package/dist/cjs/init/utils/version.cjs +0 -1
  93. package/dist/cjs/init/utils/version.cjs.map +1 -1
  94. package/dist/cjs/initConfig/index.cjs +12 -8
  95. package/dist/cjs/initConfig/index.cjs.map +1 -1
  96. package/dist/cjs/installSkills/index.cjs.map +1 -1
  97. package/dist/cjs/listDictionariesPath.cjs +6 -5
  98. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  99. package/dist/cjs/listGitFiles.cjs.map +1 -1
  100. package/dist/cjs/listProjects.cjs +2 -1
  101. package/dist/cjs/listProjects.cjs.map +1 -1
  102. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +2 -1
  103. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
  104. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +8 -5
  105. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  106. package/dist/cjs/loadDictionaries/loadDictionaries.cjs +4 -2
  107. package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
  108. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
  109. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
  110. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +3 -2
  111. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  112. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +2 -1
  113. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
  114. package/dist/cjs/loadDictionaries/log.cjs +38 -11
  115. package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
  116. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  117. package/dist/cjs/logConfigDetails.cjs +4 -3
  118. package/dist/cjs/logConfigDetails.cjs.map +1 -1
  119. package/dist/cjs/prepareIntlayer.cjs +5 -3
  120. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  121. package/dist/cjs/reduceDictionaryContent/applyMask.cjs +0 -1
  122. package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
  123. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +2 -1
  124. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
  125. package/dist/cjs/scan/calculateScore.cjs +0 -1
  126. package/dist/cjs/scan/calculateScore.cjs.map +1 -1
  127. package/dist/cjs/scan/checks.cjs +1 -1
  128. package/dist/cjs/scan/checks.cjs.map +1 -1
  129. package/dist/cjs/scan/parseHtml.cjs +0 -1
  130. package/dist/cjs/scan/parseHtml.cjs.map +1 -1
  131. package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
  132. package/dist/cjs/syncPluginKit/createFileAdapter.cjs +2 -1
  133. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
  134. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +4 -1
  135. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
  136. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +0 -1
  137. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
  138. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +0 -1
  139. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
  140. package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
  141. package/dist/cjs/utils/babelParser.cjs.map +1 -1
  142. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  143. package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
  144. package/dist/cjs/utils/chunkArray.cjs +23 -0
  145. package/dist/cjs/utils/chunkArray.cjs.map +1 -0
  146. package/dist/cjs/utils/formatter.cjs.map +1 -1
  147. package/dist/cjs/utils/getContentExtension.cjs +1 -4
  148. package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
  149. package/dist/cjs/utils/getFormatFromExtension.cjs +0 -1
  150. package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
  151. package/dist/cjs/utils/getPathHash.cjs +0 -1
  152. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  153. package/dist/cjs/utils/index.cjs +2 -0
  154. package/dist/cjs/utils/mergeChunks.cjs +0 -1
  155. package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
  156. package/dist/cjs/utils/pLimit.cjs +0 -1
  157. package/dist/cjs/utils/pLimit.cjs.map +1 -1
  158. package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
  159. package/dist/cjs/utils/reduceObjectFormat.cjs +0 -1
  160. package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
  161. package/dist/cjs/utils/resolveObjectPromises.cjs +0 -1
  162. package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
  163. package/dist/cjs/utils/resolveRelativePath.cjs +4 -1
  164. package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
  165. package/dist/cjs/utils/runOnce.cjs +2 -2
  166. package/dist/cjs/utils/runOnce.cjs.map +1 -1
  167. package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
  168. package/dist/cjs/utils/runParallel/bootstrap.cjs +0 -1
  169. package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
  170. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  171. package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
  172. package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
  173. package/dist/cjs/utils/sortAlphabetically.cjs +0 -1
  174. package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
  175. package/dist/cjs/utils/splitTextByLine.cjs +0 -1
  176. package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
  177. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs +0 -1
  178. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
  179. package/dist/cjs/watcher.cjs +4 -2
  180. package/dist/cjs/watcher.cjs.map +1 -1
  181. package/dist/cjs/writeConfiguration/index.cjs +2 -1
  182. package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
  183. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +0 -1
  184. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
  185. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
  186. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +173 -109
  187. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
  188. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs +6 -5
  189. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
  190. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +9 -3
  191. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  192. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +2 -1
  193. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
  194. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -1
  195. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  196. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +4 -2
  197. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  198. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  199. package/dist/esm/_virtual/_utils_asset.mjs +2 -1
  200. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs +15 -3
  201. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs.map +1 -1
  202. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +26 -5
  203. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
  204. package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs +43 -6
  205. package/dist/esm/buildIntlayerDictionary/writeFetchDictionary.mjs.map +1 -1
  206. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
  207. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
  208. package/dist/esm/buildIntlayerDictionary/writeNestedDictionary.mjs +92 -0
  209. package/dist/esm/buildIntlayerDictionary/writeNestedDictionary.mjs.map +1 -0
  210. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +4 -2
  211. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
  212. package/dist/esm/cleanRemovedContentDeclaration.mjs +7 -4
  213. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  214. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs +5 -3
  215. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
  216. package/dist/esm/createType/createModuleAugmentation.mjs +2 -1
  217. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  218. package/dist/esm/docReview/alignBlocks.mjs +1 -1
  219. package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
  220. package/dist/esm/docReview/reviewReport.mjs +2 -1
  221. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  222. package/dist/esm/fetchDistantDictionaries.mjs +107 -13
  223. package/dist/esm/fetchDistantDictionaries.mjs.map +1 -1
  224. package/dist/esm/handleAdditionalContentDeclarationFile.mjs +4 -2
  225. package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
  226. package/dist/esm/handleContentDeclarationFileChange.mjs +6 -2
  227. package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
  228. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +4 -2
  229. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
  230. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +1 -3
  231. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  232. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +2 -1
  233. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
  234. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +4 -6
  235. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  236. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -1
  237. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
  238. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +17 -10
  239. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
  240. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +59 -16
  241. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  242. package/dist/esm/init/index.mjs +66 -38
  243. package/dist/esm/init/index.mjs.map +1 -1
  244. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  245. package/dist/esm/init/utils/fileSystem.mjs +3 -1
  246. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  247. package/dist/esm/init/utils/packageManager.mjs +4 -2
  248. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  249. package/dist/esm/initConfig/index.mjs +12 -8
  250. package/dist/esm/initConfig/index.mjs.map +1 -1
  251. package/dist/esm/listDictionariesPath.mjs +6 -5
  252. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  253. package/dist/esm/listProjects.mjs +2 -1
  254. package/dist/esm/listProjects.mjs.map +1 -1
  255. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs +2 -1
  256. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
  257. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +8 -5
  258. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  259. package/dist/esm/loadDictionaries/loadDictionaries.mjs +4 -2
  260. package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
  261. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +3 -2
  262. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
  263. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs +2 -1
  264. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
  265. package/dist/esm/loadDictionaries/log.mjs +38 -11
  266. package/dist/esm/loadDictionaries/log.mjs.map +1 -1
  267. package/dist/esm/logConfigDetails.mjs +4 -3
  268. package/dist/esm/logConfigDetails.mjs.map +1 -1
  269. package/dist/esm/prepareIntlayer.mjs +5 -3
  270. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  271. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs +2 -1
  272. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
  273. package/dist/esm/scan/checks.mjs +1 -1
  274. package/dist/esm/scan/checks.mjs.map +1 -1
  275. package/dist/esm/syncPluginKit/createFileAdapter.mjs +2 -1
  276. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
  277. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +4 -1
  278. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
  279. package/dist/esm/utils/babelParser.mjs.map +1 -1
  280. package/dist/esm/utils/chunkArray.mjs +22 -0
  281. package/dist/esm/utils/chunkArray.mjs.map +1 -0
  282. package/dist/esm/utils/getContentExtension.mjs +1 -3
  283. package/dist/esm/utils/getContentExtension.mjs.map +1 -1
  284. package/dist/esm/utils/index.mjs +2 -1
  285. package/dist/esm/utils/resolveRelativePath.mjs +4 -1
  286. package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
  287. package/dist/esm/utils/runOnce.mjs +2 -2
  288. package/dist/esm/utils/runOnce.mjs.map +1 -1
  289. package/dist/esm/watcher.mjs +4 -2
  290. package/dist/esm/watcher.mjs.map +1 -1
  291. package/dist/esm/writeConfiguration/index.mjs +2 -1
  292. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  293. package/dist/esm/writeContentDeclaration/transformJSFile.mjs +173 -109
  294. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  295. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs +6 -5
  296. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
  297. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +9 -3
  298. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  299. package/dist/esm/writeContentDeclaration/writeJSFile.mjs +2 -1
  300. package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
  301. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -1
  302. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  303. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +4 -2
  304. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  305. package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts.map +1 -1
  306. package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts +14 -2
  307. package/dist/types/buildIntlayerDictionary/writeDynamicDictionary.d.ts.map +1 -1
  308. package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts +16 -2
  309. package/dist/types/buildIntlayerDictionary/writeFetchDictionary.d.ts.map +1 -1
  310. package/dist/types/buildIntlayerDictionary/writeNestedDictionary.d.ts +54 -0
  311. package/dist/types/buildIntlayerDictionary/writeNestedDictionary.d.ts.map +1 -0
  312. package/dist/types/fetchDistantDictionaries.d.ts +26 -0
  313. package/dist/types/fetchDistantDictionaries.d.ts.map +1 -1
  314. package/dist/types/formatDictionary.d.ts +2 -0
  315. package/dist/types/formatDictionary.d.ts.map +1 -1
  316. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +9 -4
  317. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  318. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +6 -2
  319. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  320. package/dist/types/loadDictionaries/log.d.ts +16 -1
  321. package/dist/types/loadDictionaries/log.d.ts.map +1 -1
  322. package/dist/types/utils/chunkArray.d.ts +16 -0
  323. package/dist/types/utils/chunkArray.d.ts.map +1 -0
  324. package/dist/types/utils/index.d.ts +2 -1
  325. package/dist/types/writeContentDeclaration/transformJSFile.d.ts.map +1 -1
  326. package/package.json +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"fileSystem.cjs","names":["ALL_LOCALES","EXCLUDED_PATHS","sep"],"sources":["../../../../src/init/utils/fileSystem.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative, resolve, sep } from 'node:path';\nimport { EXCLUDED_PATHS } from '@intlayer/config/defaultValues';\nimport { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport fg from 'fast-glob';\n\n/**\n * Helper to check if a file exists\n */\nexport const exists = async (rootDir: string, filePath: string) => {\n try {\n await access(join(rootDir, filePath));\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Helper to read a file\n */\nexport const readFileFromRoot = async (rootDir: string, filePath: string) =>\n await readFile(join(rootDir, filePath), 'utf8');\n\n/**\n * Helper to write a file\n */\nexport const writeFileToRoot = async (\n rootDir: string,\n filePath: string,\n content: string\n) => await writeFile(join(rootDir, filePath), content, 'utf8');\n\n/**\n * Helper to ensure a directory exists\n */\nexport const ensureDirectory = async (rootDir: string, dirPath: string) => {\n try {\n await mkdir(join(rootDir, dirPath), { recursive: true });\n } catch {\n // Directory already exists or could not be created\n }\n};\n\n/**\n * Pattern type for locale JSON file organisation.\n * - 'nested': files are at `{base}/{locale}/{key}.json`\n * - 'flat': files are at `{base}/{locale}.json`\n */\nexport type JsonLocalePatternType = 'nested' | 'flat';\n\n/**\n * Detected locale JSON file pattern and the corresponding source template.\n * `template` uses `${locale}` and `${key}` as literal placeholders (not JS\n * expressions) so it can be embedded directly in a template-literal string.\n */\nexport type JsonLocalePattern = {\n type: JsonLocalePatternType;\n /**\n * Source path template for syncJSON `source` option.\n * Example nested: `./locales/${locale}/${key}.json`\n * Example flat: `./locales/${locale}.json`\n */\n template: string;\n /**\n * Detected locales in the directory.\n */\n locales: string[];\n};\n\n/**\n * Set of all known locale string values from the intlayer Locales registry\n * (e.g. `'en'`, `'fr'`, `'zh-TW'`). Keyed by the exact locale string so\n * `.has()` lookups are O(1) and common short directory names (`src`, `lib`,\n * `app`, …) are not mistaken for locales.\n */\nconst ALL_LOCALE_VALUES = new Set<string>(Object.values(ALL_LOCALES));\n\n/**\n * Returns true when `segment` matches a known BCP-47 locale identifier, e.g.\n * `en`, `fr`, `zh-TW`, `pt-BR`, `en-US`.\n */\nconst isLocaleSegment = (segment: string): boolean =>\n ALL_LOCALE_VALUES.has(segment);\n\n/** JSON filenames that are never locale translation files. */\nconst KNOWN_CONFIG_FILENAMES = new Set([\n 'package.json',\n 'tsconfig.json',\n 'jsconfig.json',\n 'biome.json',\n 'turbo.json',\n 'lerna.json',\n 'vercel.json',\n 'netlify.json',\n 'babel.config.json',\n 'jest.config.json',\n 'vitest.config.json',\n '.eslintrc.json',\n '.prettierrc.json',\n]);\n\n/**\n * Scans the project for JSON files and determines whether locale files are\n * organised as `{base}/{locale}/{key}.json` (nested) or `{base}/{locale}.json`\n * (flat). Returns the most likely source template, or `null` when no locale\n * JSON files are found.\n *\n * The returned `template` contains `${locale}` and `${key}` as **literal**\n * placeholder strings so it can be embedded inside a JS template literal.\n */\nexport const detectJsonLocalePattern = async (\n rootDir: string\n): Promise<JsonLocalePattern | null> => {\n const files = await fg('**/*.json', {\n cwd: rootDir,\n ignore: EXCLUDED_PATHS,\n absolute: false,\n onlyFiles: true,\n });\n\n const nestedBasePaths: string[] = [];\n const flatBasePaths: string[] = [];\n const nestedLocales = new Set<string>();\n const flatLocales = new Set<string>();\n\n for (const file of files) {\n const parts = file.split('/');\n const filename = parts[parts.length - 1] ?? '';\n\n if (KNOWN_CONFIG_FILENAMES.has(filename)) continue;\n\n // Nested: …/{locale}/{key}.json — parent directory is a locale code\n if (parts.length >= 3) {\n const localeDir = parts[parts.length - 2] ?? '';\n if (isLocaleSegment(localeDir)) {\n nestedBasePaths.push(parts.slice(0, -2).join('/') || '.');\n nestedLocales.add(localeDir);\n }\n }\n\n // Flat: …/{locale}.json — filename (without extension) is a locale code\n if (parts.length >= 2) {\n const baseName = filename.slice(0, -5); // strip \".json\"\n if (isLocaleSegment(baseName)) {\n flatBasePaths.push(parts.slice(0, -1).join('/') || '.');\n flatLocales.add(baseName);\n }\n }\n }\n\n if (nestedBasePaths.length === 0 && flatBasePaths.length === 0) {\n return null;\n }\n\n /**\n * Returns the path prefix that appears most frequently among the matches,\n * formatted as a relative path suitable for a source template.\n */\n const mostFrequentPrefix = (paths: string[]): string => {\n const counts = paths.reduce<Record<string, number>>((accumulator, path) => {\n accumulator[path] = (accumulator[path] ?? 0) + 1;\n return accumulator;\n }, {});\n const topEntry = Object.entries(counts).sort(([, a], [, b]) => b - a)[0];\n const basePath = topEntry?.[0] ?? '.';\n return basePath === '.' ? '.' : `./${basePath}`;\n };\n\n if (nestedBasePaths.length >= flatBasePaths.length) {\n const prefix = mostFrequentPrefix(nestedBasePaths);\n return {\n type: 'nested',\n // Literal ${locale} and ${key} — not evaluated here, used in template literals\n template: `${prefix}/\\${locale}/\\${key}.json`,\n locales: Array.from(nestedLocales),\n };\n }\n\n const prefix = mostFrequentPrefix(flatBasePaths);\n return {\n type: 'flat',\n template: `${prefix}/\\${locale}.json`,\n locales: Array.from(flatLocales),\n };\n};\n\n/**\n * Detected lingui catalog pattern. lingui stores one catalog file per locale\n * (default name `messages`), as `.po` (its default) or `.json`.\n */\nexport type LinguiCatalogPattern = {\n /** Which sync plugin should ingest the catalogs. */\n format: 'po' | 'json';\n /**\n * Source path template, with `${locale}` and `${key}` as literal\n * placeholders. The catalog filename (`messages`) is captured by `${key}` so\n * the produced intlayer dictionary key is `messages` — matching the fixed\n * `messages` namespace the lingui compat runtime reads from.\n * Example: `./src/locales/${locale}/${key}.po`.\n */\n template: string;\n /** Detected locales. */\n locales: string[];\n};\n\n/**\n * Scans the project for lingui catalog files (`{base}/{locale}/messages.po` or\n * `…/messages.json`, lingui's default layout) and derives the `syncPO` /\n * `syncJSON` `source` template.\n *\n * `.po` is preferred when present (lingui's default format). Returns `null`\n * when no lingui catalog is found, in which case the caller falls back to the\n * generic JSON detection.\n *\n * @param rootDir - Project root directory.\n */\nexport const detectLinguiCatalogPattern = async (\n rootDir: string\n): Promise<LinguiCatalogPattern | null> => {\n // lingui's default catalog name is `messages`; match that basename for both\n // formats so the captured `${key}` is `messages`.\n const files = await fg(['**/messages.po', '**/messages.json'], {\n cwd: rootDir,\n ignore: EXCLUDED_PATHS,\n absolute: false,\n onlyFiles: true,\n });\n\n const basePathsByFormat: Record<'po' | 'json', string[]> = {\n po: [],\n json: [],\n };\n const localesByFormat: Record<'po' | 'json', Set<string>> = {\n po: new Set(),\n json: new Set(),\n };\n\n for (const file of files) {\n const parts = file.split('/');\n // Nested layout: …/{locale}/messages.{po,json} — parent dir is the locale.\n if (parts.length < 2) continue;\n\n const localeDir = parts[parts.length - 2] ?? '';\n if (!isLocaleSegment(localeDir)) continue;\n\n const extension = (file.endsWith('.po') ? 'po' : 'json') as 'po' | 'json';\n basePathsByFormat[extension].push(parts.slice(0, -2).join('/') || '.');\n localesByFormat[extension].add(localeDir);\n }\n\n // Prefer `.po` (lingui's default) when catalogs of both formats coexist.\n const format: 'po' | 'json' = basePathsByFormat.po.length > 0 ? 'po' : 'json';\n\n const basePaths = basePathsByFormat[format];\n if (basePaths.length === 0) return null;\n\n const counts = basePaths.reduce<Record<string, number>>(\n (accumulator, path) => {\n accumulator[path] = (accumulator[path] ?? 0) + 1;\n return accumulator;\n },\n {}\n );\n const topBasePath =\n Object.entries(counts).sort(([, a], [, b]) => b - a)[0]?.[0] ?? '.';\n const prefix = topBasePath === '.' ? '.' : `./${topBasePath}`;\n\n return {\n format,\n template: `${prefix}/\\${locale}/\\${key}.${format}`,\n locales: Array.from(localesByFormat[format]),\n };\n};\n\n/**\n * The messages source template derived from a `next-intl` `i18n/request.ts`\n * file, ready to be used as a `syncJSON` `source` builder.\n */\nexport type NextIntlMessagesPattern = {\n /** `'flat'` (one file per locale) or `'nested'` (per-namespace files). */\n type: JsonLocalePatternType;\n /**\n * Source path template relative to the project root, with `${locale}` (and\n * `${key}` when nested) as literal placeholders, e.g. `./messages/${locale}.json`.\n */\n template: string;\n};\n\n/** Common locations of the `next-intl` request config, relative to the root. */\nconst NEXT_INTL_REQUEST_FILES = [\n 'i18n/request.ts',\n 'i18n/request.tsx',\n 'i18n/request.js',\n 'i18n/request.mjs',\n 'src/i18n/request.ts',\n 'src/i18n/request.tsx',\n 'src/i18n/request.js',\n 'src/i18n/request.mjs',\n 'app/i18n/request.ts',\n 'src/app/i18n/request.ts',\n];\n\n/**\n * Derives the messages source template from a `next-intl` `i18n/request.ts`\n * file, which is the authoritative location of the messages path in a next-intl\n * project (e.g. `messages: (await import(\\`../messages/${locale}.json\\`)).default`).\n *\n * Reading it removes the ambiguity of globbing the file system and yields the\n * exact `source` template for `syncJSON`. When the resulting template has no\n * `${key}` segment (the common single-file-per-locale layout, where top-level\n * keys are namespaces), `syncJSON` `splitKeys` auto-detection turns each\n * top-level key into its own dictionary.\n *\n * Returns `null` when no request file is found, the messages import cannot be\n * parsed, or the path is not project-root-relative (e.g. uses a TS path alias).\n *\n * @param rootDir - Project root directory.\n */\nexport const detectNextIntlMessagesPattern = async (\n rootDir: string\n): Promise<NextIntlMessagesPattern | null> => {\n for (const requestFile of NEXT_INTL_REQUEST_FILES) {\n if (!(await exists(rootDir, requestFile))) continue;\n\n const content = await readFileFromRoot(rootDir, requestFile);\n\n // Capture the template-literal path of the messages dynamic import, e.g.\n // import(`../messages/${locale}.json`) → `../messages/${locale}.json`.\n const importMatch = content.match(\n /import\\(\\s*`([^`]*\\$\\{\\s*locale\\s*\\}[^`]*\\.json)`/\n );\n\n const importPath = importMatch?.[1];\n if (!importPath) continue;\n\n // Only relative imports can be resolved against the file system; path\n // aliases (e.g. `@/messages/...`) are skipped in favour of glob detection.\n if (!importPath.startsWith('.')) continue;\n\n // Resolve the import (relative to the request file) back to a\n // project-root-relative template. The `${locale}` / `${key}` placeholders\n // are kept literal — path utilities treat them as ordinary segments.\n const requestDir = dirname(resolve(rootDir, requestFile));\n const absoluteTemplate = resolve(requestDir, importPath);\n const relativeTemplate = relative(rootDir, absoluteTemplate)\n .split(sep)\n .join('/');\n\n const template = relativeTemplate.startsWith('.')\n ? relativeTemplate\n : `./${relativeTemplate}`;\n\n const type: JsonLocalePatternType =\n template.includes('${key}') || template.includes('${namespace}')\n ? 'nested'\n : 'flat';\n\n return { type, template };\n }\n\n return null;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"fileSystem.cjs","names":["access","join","readFile","writeFile","mkdir","ALL_LOCALES","fg","EXCLUDED_PATHS","dirname","resolve","relative","sep"],"sources":["../../../../src/init/utils/fileSystem.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative, resolve, sep } from 'node:path';\nimport { EXCLUDED_PATHS } from '@intlayer/config/defaultValues';\nimport { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport fg from 'fast-glob';\n\n/**\n * Helper to check if a file exists\n */\nexport const exists = async (rootDir: string, filePath: string) => {\n try {\n await access(join(rootDir, filePath));\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Helper to read a file\n */\nexport const readFileFromRoot = async (rootDir: string, filePath: string) =>\n await readFile(join(rootDir, filePath), 'utf8');\n\n/**\n * Helper to write a file\n */\nexport const writeFileToRoot = async (\n rootDir: string,\n filePath: string,\n content: string\n) => await writeFile(join(rootDir, filePath), content, 'utf8');\n\n/**\n * Helper to ensure a directory exists\n */\nexport const ensureDirectory = async (rootDir: string, dirPath: string) => {\n try {\n await mkdir(join(rootDir, dirPath), { recursive: true });\n } catch {\n // Directory already exists or could not be created\n }\n};\n\n/**\n * Pattern type for locale JSON file organisation.\n * - 'nested': files are at `{base}/{locale}/{key}.json`\n * - 'flat': files are at `{base}/{locale}.json`\n */\nexport type JsonLocalePatternType = 'nested' | 'flat';\n\n/**\n * Detected locale JSON file pattern and the corresponding source template.\n * `template` uses `${locale}` and `${key}` as literal placeholders (not JS\n * expressions) so it can be embedded directly in a template-literal string.\n */\nexport type JsonLocalePattern = {\n type: JsonLocalePatternType;\n /**\n * Source path template for syncJSON `source` option.\n * Example nested: `./locales/${locale}/${key}.json`\n * Example flat: `./locales/${locale}.json`\n */\n template: string;\n /**\n * Detected locales in the directory.\n */\n locales: string[];\n};\n\n/**\n * Set of all known locale string values from the intlayer Locales registry\n * (e.g. `'en'`, `'fr'`, `'zh-TW'`). Keyed by the exact locale string so\n * `.has()` lookups are O(1) and common short directory names (`src`, `lib`,\n * `app`, …) are not mistaken for locales.\n */\nconst ALL_LOCALE_VALUES = new Set<string>(Object.values(ALL_LOCALES));\n\n/**\n * Returns true when `segment` matches a known BCP-47 locale identifier, e.g.\n * `en`, `fr`, `zh-TW`, `pt-BR`, `en-US`.\n */\nconst isLocaleSegment = (segment: string): boolean =>\n ALL_LOCALE_VALUES.has(segment);\n\n/** JSON filenames that are never locale translation files. */\nconst KNOWN_CONFIG_FILENAMES = new Set([\n 'package.json',\n 'tsconfig.json',\n 'jsconfig.json',\n 'biome.json',\n 'turbo.json',\n 'lerna.json',\n 'vercel.json',\n 'netlify.json',\n 'babel.config.json',\n 'jest.config.json',\n 'vitest.config.json',\n '.eslintrc.json',\n '.prettierrc.json',\n]);\n\n/**\n * Scans the project for JSON files and determines whether locale files are\n * organised as `{base}/{locale}/{key}.json` (nested) or `{base}/{locale}.json`\n * (flat). Returns the most likely source template, or `null` when no locale\n * JSON files are found.\n *\n * The returned `template` contains `${locale}` and `${key}` as **literal**\n * placeholder strings so it can be embedded inside a JS template literal.\n */\nexport const detectJsonLocalePattern = async (\n rootDir: string\n): Promise<JsonLocalePattern | null> => {\n const files = await fg('**/*.json', {\n cwd: rootDir,\n ignore: EXCLUDED_PATHS,\n absolute: false,\n onlyFiles: true,\n });\n\n const nestedBasePaths: string[] = [];\n const flatBasePaths: string[] = [];\n const nestedLocales = new Set<string>();\n const flatLocales = new Set<string>();\n\n for (const file of files) {\n const parts = file.split('/');\n const filename = parts[parts.length - 1] ?? '';\n\n if (KNOWN_CONFIG_FILENAMES.has(filename)) continue;\n\n // Nested: …/{locale}/{key}.json — parent directory is a locale code\n if (parts.length >= 3) {\n const localeDir = parts[parts.length - 2] ?? '';\n if (isLocaleSegment(localeDir)) {\n nestedBasePaths.push(parts.slice(0, -2).join('/') || '.');\n nestedLocales.add(localeDir);\n }\n }\n\n // Flat: …/{locale}.json — filename (without extension) is a locale code\n if (parts.length >= 2) {\n const baseName = filename.slice(0, -5); // strip \".json\"\n if (isLocaleSegment(baseName)) {\n flatBasePaths.push(parts.slice(0, -1).join('/') || '.');\n flatLocales.add(baseName);\n }\n }\n }\n\n if (nestedBasePaths.length === 0 && flatBasePaths.length === 0) {\n return null;\n }\n\n /**\n * Returns the path prefix that appears most frequently among the matches,\n * formatted as a relative path suitable for a source template.\n */\n const mostFrequentPrefix = (paths: string[]): string => {\n const counts = paths.reduce<Record<string, number>>((accumulator, path) => {\n accumulator[path] = (accumulator[path] ?? 0) + 1;\n return accumulator;\n }, {});\n const topEntry = Object.entries(counts).sort(([, a], [, b]) => b - a)[0];\n const basePath = topEntry?.[0] ?? '.';\n return basePath === '.' ? '.' : `./${basePath}`;\n };\n\n if (nestedBasePaths.length >= flatBasePaths.length) {\n const prefix = mostFrequentPrefix(nestedBasePaths);\n return {\n type: 'nested',\n // Literal ${locale} and ${key} — not evaluated here, used in template literals\n template: `${prefix}/\\${locale}/\\${key}.json`,\n locales: Array.from(nestedLocales),\n };\n }\n\n const prefix = mostFrequentPrefix(flatBasePaths);\n return {\n type: 'flat',\n template: `${prefix}/\\${locale}.json`,\n locales: Array.from(flatLocales),\n };\n};\n\n/**\n * Detected lingui catalog pattern. lingui stores one catalog file per locale\n * (default name `messages`), as `.po` (its default) or `.json`.\n */\nexport type LinguiCatalogPattern = {\n /** Which sync plugin should ingest the catalogs. */\n format: 'po' | 'json';\n /**\n * Source path template, with `${locale}` and `${key}` as literal\n * placeholders. The catalog filename (`messages`) is captured by `${key}` so\n * the produced intlayer dictionary key is `messages` — matching the fixed\n * `messages` namespace the lingui compat runtime reads from.\n * Example: `./src/locales/${locale}/${key}.po`.\n */\n template: string;\n /** Detected locales. */\n locales: string[];\n};\n\n/**\n * Scans the project for lingui catalog files (`{base}/{locale}/messages.po` or\n * `…/messages.json`, lingui's default layout) and derives the `syncPO` /\n * `syncJSON` `source` template.\n *\n * `.po` is preferred when present (lingui's default format). Returns `null`\n * when no lingui catalog is found, in which case the caller falls back to the\n * generic JSON detection.\n *\n * @param rootDir - Project root directory.\n */\nexport const detectLinguiCatalogPattern = async (\n rootDir: string\n): Promise<LinguiCatalogPattern | null> => {\n // lingui's default catalog name is `messages`; match that basename for both\n // formats so the captured `${key}` is `messages`.\n const files = await fg(['**/messages.po', '**/messages.json'], {\n cwd: rootDir,\n ignore: EXCLUDED_PATHS,\n absolute: false,\n onlyFiles: true,\n });\n\n const basePathsByFormat: Record<'po' | 'json', string[]> = {\n po: [],\n json: [],\n };\n const localesByFormat: Record<'po' | 'json', Set<string>> = {\n po: new Set(),\n json: new Set(),\n };\n\n for (const file of files) {\n const parts = file.split('/');\n // Nested layout: …/{locale}/messages.{po,json} — parent dir is the locale.\n if (parts.length < 2) continue;\n\n const localeDir = parts[parts.length - 2] ?? '';\n if (!isLocaleSegment(localeDir)) continue;\n\n const extension = (file.endsWith('.po') ? 'po' : 'json') as 'po' | 'json';\n basePathsByFormat[extension].push(parts.slice(0, -2).join('/') || '.');\n localesByFormat[extension].add(localeDir);\n }\n\n // Prefer `.po` (lingui's default) when catalogs of both formats coexist.\n const format: 'po' | 'json' = basePathsByFormat.po.length > 0 ? 'po' : 'json';\n\n const basePaths = basePathsByFormat[format];\n if (basePaths.length === 0) return null;\n\n const counts = basePaths.reduce<Record<string, number>>(\n (accumulator, path) => {\n accumulator[path] = (accumulator[path] ?? 0) + 1;\n return accumulator;\n },\n {}\n );\n const topBasePath =\n Object.entries(counts).sort(([, a], [, b]) => b - a)[0]?.[0] ?? '.';\n const prefix = topBasePath === '.' ? '.' : `./${topBasePath}`;\n\n return {\n format,\n template: `${prefix}/\\${locale}/\\${key}.${format}`,\n locales: Array.from(localesByFormat[format]),\n };\n};\n\n/**\n * The messages source template derived from a `next-intl` `i18n/request.ts`\n * file, ready to be used as a `syncJSON` `source` builder.\n */\nexport type NextIntlMessagesPattern = {\n /** `'flat'` (one file per locale) or `'nested'` (per-namespace files). */\n type: JsonLocalePatternType;\n /**\n * Source path template relative to the project root, with `${locale}` (and\n * `${key}` when nested) as literal placeholders, e.g. `./messages/${locale}.json`.\n */\n template: string;\n};\n\n/** Common locations of the `next-intl` request config, relative to the root. */\nconst NEXT_INTL_REQUEST_FILES = [\n 'i18n/request.ts',\n 'i18n/request.tsx',\n 'i18n/request.js',\n 'i18n/request.mjs',\n 'src/i18n/request.ts',\n 'src/i18n/request.tsx',\n 'src/i18n/request.js',\n 'src/i18n/request.mjs',\n 'app/i18n/request.ts',\n 'src/app/i18n/request.ts',\n];\n\n/**\n * Derives the messages source template from a `next-intl` `i18n/request.ts`\n * file, which is the authoritative location of the messages path in a next-intl\n * project (e.g. `messages: (await import(\\`../messages/${locale}.json\\`)).default`).\n *\n * Reading it removes the ambiguity of globbing the file system and yields the\n * exact `source` template for `syncJSON`. When the resulting template has no\n * `${key}` segment (the common single-file-per-locale layout, where top-level\n * keys are namespaces), `syncJSON` `splitKeys` auto-detection turns each\n * top-level key into its own dictionary.\n *\n * Returns `null` when no request file is found, the messages import cannot be\n * parsed, or the path is not project-root-relative (e.g. uses a TS path alias).\n *\n * @param rootDir - Project root directory.\n */\nexport const detectNextIntlMessagesPattern = async (\n rootDir: string\n): Promise<NextIntlMessagesPattern | null> => {\n for (const requestFile of NEXT_INTL_REQUEST_FILES) {\n if (!(await exists(rootDir, requestFile))) continue;\n\n const content = await readFileFromRoot(rootDir, requestFile);\n\n // Capture the template-literal path of the messages dynamic import, e.g.\n // import(`../messages/${locale}.json`) → `../messages/${locale}.json`.\n const importMatch = content.match(\n /import\\(\\s*`([^`]*\\$\\{\\s*locale\\s*\\}[^`]*\\.json)`/\n );\n\n const importPath = importMatch?.[1];\n if (!importPath) continue;\n\n // Only relative imports can be resolved against the file system; path\n // aliases (e.g. `@/messages/...`) are skipped in favour of glob detection.\n if (!importPath.startsWith('.')) continue;\n\n // Resolve the import (relative to the request file) back to a\n // project-root-relative template. The `${locale}` / `${key}` placeholders\n // are kept literal — path utilities treat them as ordinary segments.\n const requestDir = dirname(resolve(rootDir, requestFile));\n const absoluteTemplate = resolve(requestDir, importPath);\n const relativeTemplate = relative(rootDir, absoluteTemplate)\n .split(sep)\n .join('/');\n\n const template = relativeTemplate.startsWith('.')\n ? relativeTemplate\n : `./${relativeTemplate}`;\n\n const type: JsonLocalePatternType =\n template.includes('${key}') || template.includes('${namespace}')\n ? 'nested'\n : 'flat';\n\n return { type, template };\n }\n\n return null;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"githubActions.cjs","names":["getGitRootDir","listProjects","detectPackageManager","sep"],"sources":["../../../../src/init/utils/githubActions.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\nimport { getGitRootDir, listProjects } from '../../listProjects';\nimport { detectPackageManager, type PackageManager } from './packageManager';\n\n/** A GitHub Actions workflow file to be written to the project. */\nexport type GithubWorkflowFile = {\n /** Path relative to the project root, e.g. `.github/workflows/intlayer-fill.yml`. */\n filePath: string;\n /** Full YAML content of the workflow file. */\n content: string;\n};\n\n/** Options controlling how the CI workflows are generated. */\nexport type GithubWorkflowsOptions = {\n /**\n * Route the intlayer commands through `intlayer ci` instead of calling them\n * directly. The `ci` command discovers every Intlayer project of the\n * repository (via `listProjects`) and runs the given command inside each of\n * them, injecting per-project credentials from the\n * `INTLAYER_PROJECT_CREDENTIALS` secret when provided. Required for\n * monorepos where a single workflow must cover several projects.\n */\n useCiCommand?: boolean;\n /**\n * Repository-relative directory (posix separators) the workflow commands run\n * in. Set when the Intlayer project lives in a subdirectory of the\n * repository and the repository root has no workspace manifest to install\n * dependencies from. Undefined = repository root.\n */\n workingDirectory?: string;\n};\n\n/**\n * Resolved placement and generation parameters for the CI workflows.\n * See {@link resolveGithubWorkflowsContext}.\n */\nexport type GithubWorkflowsContext = {\n /**\n * Directory the workflow files must be written to. GitHub only triggers\n * workflows stored in `.github/workflows` at the repository root, so this is\n * the git root whenever the project lives inside a git repository.\n */\n workflowsRootDir: string;\n /** Package manager whose commands are baked into the workflows. */\n packageManager: PackageManager;\n /** Generation options forwarded to {@link getGithubWorkflows}. */\n options: GithubWorkflowsOptions;\n};\n\n/**\n * Returns true when the repository root hosts a workspace manifest\n * (a `package.json` `workspaces` field or a `pnpm-workspace.yaml`), meaning a\n * single install at the root covers every package of the monorepo.\n */\nconst hasWorkspaceManifest = (repositoryRootDir: string): boolean => {\n if (existsSync(join(repositoryRootDir, 'pnpm-workspace.yaml'))) {\n return true;\n }\n\n try {\n const packageJsonPath = join(repositoryRootDir, 'package.json');\n if (!existsSync(packageJsonPath)) return false;\n const { workspaces } = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return Boolean(workspaces);\n } catch {\n return false;\n }\n};\n\n/**\n * Resolves where the CI workflows must be written and how their commands must\n * be generated, based on the repository layout around `rootDir` (the Intlayer\n * project being initialized):\n *\n * - Project at the repository root: workflows are written in place. When the\n * repository is a monorepo (workspace manifest, or several Intlayer projects\n * discovered by `listProjects`), the commands go through `intlayer ci` so\n * every project is covered.\n * - Project nested in a repository whose root has a `package.json`\n * (workspace-managed monorepo): workflows are written at the git root —\n * GitHub ignores `.github/workflows` in subdirectories — dependencies are\n * installed at the root with the root's package manager, and the commands go\n * through `intlayer ci` to iterate every Intlayer project.\n * - Project nested in a repository without a root `package.json`: workflows\n * are written at the git root but run inside the project directory\n * (`working-directory`), keeping the project's own package manager.\n */\nexport const resolveGithubWorkflowsContext = async (\n rootDir: string,\n projectPackageManager: PackageManager\n): Promise<GithubWorkflowsContext> => {\n const projectRootDir = resolve(rootDir);\n\n let repositoryRootDir = projectRootDir;\n try {\n const gitRootDir = await getGitRootDir(projectRootDir);\n if (gitRootDir) repositoryRootDir = resolve(gitRootDir);\n } catch {\n // Not a git repository — keep the project root as the workflow root.\n }\n\n // Discover every Intlayer project of the repository. `listProjects` scans\n // for configuration files, so a fresh project whose config is created later\n // in the init flow may not be counted yet — the workspace manifest check\n // below still catches that monorepo case.\n let repositoryProjectCount = 0;\n try {\n const { projectsPath } = await listProjects({\n baseDir: repositoryRootDir,\n });\n repositoryProjectCount = projectsPath.length;\n } catch {\n repositoryProjectCount = 0;\n }\n\n const isNestedProject = repositoryRootDir !== projectRootDir;\n const isWorkspaceRepository = hasWorkspaceManifest(repositoryRootDir);\n const hasRootPackageJson = existsSync(\n join(repositoryRootDir, 'package.json')\n );\n\n if (!isNestedProject) {\n return {\n workflowsRootDir: projectRootDir,\n packageManager: projectPackageManager,\n options: {\n useCiCommand: isWorkspaceRepository || repositoryProjectCount > 1,\n },\n };\n }\n\n if (hasRootPackageJson) {\n return {\n workflowsRootDir: repositoryRootDir,\n packageManager: detectPackageManager(repositoryRootDir),\n options: { useCiCommand: true },\n };\n }\n\n // Nested project without a root manifest: install and run everything inside\n // the project directory itself.\n return {\n workflowsRootDir: repositoryRootDir,\n packageManager: projectPackageManager,\n options: {\n workingDirectory: relative(repositoryRootDir, projectRootDir)\n .split(sep)\n .join('/'),\n },\n };\n};\n\n/**\n * Package-manager-specific snippets used to assemble the CI workflows.\n * - `setupSteps`: YAML steps (already indented for the `steps:` list) that\n * install the package manager and Node.js, including dependency caching.\n * - `installCommand`: command that installs the project dependencies.\n * - `execCommand`: prefix used to run the locally installed `intlayer` binary.\n */\ntype PackageManagerCIConfig = {\n setupSteps: string;\n installCommand: string;\n execCommand: string;\n};\n\n/** Dependency lock file of each package manager, used for cache invalidation. */\nconst LOCK_FILE_BY_PACKAGE_MANAGER: Record<PackageManager, string> = {\n bun: 'bun.lock',\n pnpm: 'pnpm-lock.yaml',\n yarn: 'yarn.lock',\n npm: 'package-lock.json',\n};\n\n/**\n * Returns the package-manager-specific steps and commands used to build the\n * GitHub Actions workflows. Each package manager needs a slightly different\n * setup action and a different way to run the local `intlayer` binary.\n *\n * `workingDirectory` is the repository-relative directory holding the lock\n * file when the project is nested: `actions/setup-node` looks for the lock\n * file at the repository root by default and fails the cache setup otherwise.\n */\nconst getPackageManagerCIConfig = (\n packageManager: PackageManager,\n workingDirectory?: string\n): PackageManagerCIConfig => {\n const setupNodeStep = (cache: PackageManager | undefined): string => {\n const cacheDependencyPath =\n cache && workingDirectory\n ? `\\n cache-dependency-path: ${workingDirectory}/${LOCK_FILE_BY_PACKAGE_MANAGER[cache]}`\n : '';\n\n return ` - name: 🟢 Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: 20${cache ? `\\n cache: ${cache}` : ''}${cacheDependencyPath}`;\n };\n\n switch (packageManager) {\n case 'bun':\n return {\n setupSteps: ` - name: 🥟 Setup Bun\n uses: oven-sh/setup-bun@v2`,\n installCommand: 'bun install --frozen-lockfile',\n execCommand: 'bunx intlayer',\n };\n case 'pnpm':\n return {\n setupSteps: ` - name: 📦 Setup pnpm\n uses: pnpm/action-setup@v4\n${setupNodeStep('pnpm')}`,\n installCommand: 'pnpm install --frozen-lockfile',\n execCommand: 'pnpm exec intlayer',\n };\n case 'yarn':\n return {\n setupSteps: setupNodeStep('yarn'),\n installCommand: 'yarn install --frozen-lockfile',\n execCommand: 'yarn intlayer',\n };\n case 'npm':\n return {\n setupSteps: setupNodeStep('npm'),\n installCommand: 'npm ci',\n execCommand: 'npx intlayer',\n };\n }\n};\n\n/**\n * Renders the `defaults.run.working-directory` block for jobs that must run\n * inside a nested project directory. Empty when the commands run at the\n * repository root.\n */\nconst getWorkingDirectoryBlock = (workingDirectory?: string): string =>\n workingDirectory\n ? `\n defaults:\n run:\n working-directory: ${workingDirectory}`\n : '';\n\n/**\n * Renders the env comment + optional wiring for per-project credentials in\n * monorepo (`intlayer ci`) mode. The `ci` command matches each entry of the\n * `INTLAYER_PROJECT_CREDENTIALS` JSON map to a discovered project path and\n * injects its access keys before running the command in that project.\n */\nconst getMonorepoCredentialsBlock = (useCiCommand?: boolean): string =>\n useCiCommand\n ? `\n #\n # Monorepo — per-project CMS credentials, as a JSON map of project path\n # (relative to the repository root) to access keys, e.g.\n # {\"apps/web\":{\"clientId\":\"...\",\"clientSecret\":\"...\"}}:\n # INTLAYER_PROJECT_CREDENTIALS: \\${{ secrets.INTLAYER_PROJECT_CREDENTIALS }}`\n : '';\n\n/**\n * Builds the `intlayer fill` workflow. Runs on pull requests, regenerates the\n * missing translations for the changed dictionaries (`--git-diff`) using AI,\n * then commits the result back to the PR branch.\n *\n * AI access is required for `fill`. The workflow exposes both options:\n * - a provider API key (`AI_API_KEY` secret), forwarded via CLI flags, or\n * - Intlayer CMS access keys (`INTLAYER_CLIENT_ID` / `INTLAYER_CLIENT_SECRET`).\n */\nconst generateFillWorkflow = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions\n): string => {\n const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(\n packageManager,\n options.workingDirectory\n );\n\n // In monorepo mode `intlayer ci <command>` discovers every Intlayer project\n // of the repository and runs the command inside each of them.\n const intlayerCommand = options.useCiCommand\n ? `${execCommand} ci`\n : execCommand;\n\n return `name: Intlayer Fill\n# Auto-fill missing translations on every pull request.\non:\n pull_request:\n branches:\n - main\n\npermissions:\n contents: write\n pull-requests: write\n\nconcurrency:\n group: intlayer-fill-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n fill:\n runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}\n env:\n # AI access is required to generate translations.\n # Add the secret in: Settings → Secrets and variables → Actions.\n #\n # Option 1 — Use your own AI provider key (forwarded below via CLI flags):\n AI_PROVIDER: openai\n AI_MODEL: gpt-5-mini\n AI_API_KEY: \\${{ secrets.AI_API_KEY }}\n #\n # Option 2 — Use Intlayer CMS access keys instead of your own AI key.\n # Wire them in your intlayer.config and uncomment the lines below:\n # INTLAYER_CLIENT_ID: \\${{ secrets.INTLAYER_CLIENT_ID }}\n # INTLAYER_CLIENT_SECRET: \\${{ secrets.INTLAYER_CLIENT_SECRET }}${getMonorepoCredentialsBlock(options.useCiCommand)}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n with:\n persist-credentials: true # Keep credentials to push back to the PR\n fetch-depth: 0 # Full history so --git-diff can compare refs\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${intlayerCommand} build\n - name: 🤖 Fill missing translations\n # Skip when no AI credentials are configured, so the workflow stays green\n # until an \\`AI_API_KEY\\` (or Intlayer CMS access keys) secret is added.\n if: \\${{ env.AI_API_KEY != '' || env.INTLAYER_CLIENT_ID != '' }}\n run: ${intlayerCommand} fill --git-diff --mode complete --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY\n - name: 📤 Commit and push changes\n run: |\n git config --local user.email \"github-actions[bot]@users.noreply.github.com\"\n git config --local user.name \"github-actions[bot]\"\n if [ -n \"$(git status --porcelain)\" ]; then\n git add .\n git commit -m \"chore(intlayer): fill missing translations [skip ci]\"\n git push origin HEAD:\\${{ github.head_ref }}\n else\n echo \"No missing translations to fill.\"\n fi\n`;\n};\n\n/**\n * Builds the `intlayer test` workflow. Runs on pull requests and fails the\n * check when required locales are missing translations. No AI access needed.\n */\nconst generateTestWorkflow = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions\n): string => {\n const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(\n packageManager,\n options.workingDirectory\n );\n\n // In monorepo mode `intlayer ci <command>` discovers every Intlayer project\n // of the repository and runs the command inside each of them.\n const intlayerCommand = options.useCiCommand\n ? `${execCommand} ci`\n : execCommand;\n\n return `name: Intlayer Test\n# Fail the pull request when required locales are missing translations.\non:\n pull_request:\n branches:\n - main\n\nconcurrency:\n group: intlayer-test-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n test:\n runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${intlayerCommand} build\n - name: 🧪 Test for missing translations\n run: ${intlayerCommand} test\n`;\n};\n\n/** Workflow file path constants, relative to the project root. */\nexport const GITHUB_FILL_WORKFLOW_PATH = '.github/workflows/intlayer-fill.yml';\nexport const GITHUB_TEST_WORKFLOW_PATH = '.github/workflows/intlayer-test.yml';\n\n/**\n * Returns the two Intlayer GitHub Actions workflows (`fill` and `test`),\n * generated with commands matching the detected package manager and the\n * repository layout (see {@link GithubWorkflowsOptions} for the monorepo and\n * nested-project variants).\n */\nexport const getGithubWorkflows = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions = {}\n): GithubWorkflowFile[] => [\n {\n filePath: GITHUB_FILL_WORKFLOW_PATH,\n content: generateFillWorkflow(packageManager, options),\n },\n {\n filePath: GITHUB_TEST_WORKFLOW_PATH,\n content: generateTestWorkflow(packageManager, options),\n },\n];\n"],"mappings":"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"}
1
+ {"version":3,"file":"githubActions.cjs","names":["existsSync","join","readFileSync","resolve","getGitRootDir","listProjects","detectPackageManager","relative","sep"],"sources":["../../../../src/init/utils/githubActions.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\nimport { getGitRootDir, listProjects } from '../../listProjects';\nimport { detectPackageManager, type PackageManager } from './packageManager';\n\n/** A GitHub Actions workflow file to be written to the project. */\nexport type GithubWorkflowFile = {\n /** Path relative to the project root, e.g. `.github/workflows/intlayer-fill.yml`. */\n filePath: string;\n /** Full YAML content of the workflow file. */\n content: string;\n};\n\n/** Options controlling how the CI workflows are generated. */\nexport type GithubWorkflowsOptions = {\n /**\n * Route the intlayer commands through `intlayer ci` instead of calling them\n * directly. The `ci` command discovers every Intlayer project of the\n * repository (via `listProjects`) and runs the given command inside each of\n * them, injecting per-project credentials from the\n * `INTLAYER_PROJECT_CREDENTIALS` secret when provided. Required for\n * monorepos where a single workflow must cover several projects.\n */\n useCiCommand?: boolean;\n /**\n * Repository-relative directory (posix separators) the workflow commands run\n * in. Set when the Intlayer project lives in a subdirectory of the\n * repository and the repository root has no workspace manifest to install\n * dependencies from. Undefined = repository root.\n */\n workingDirectory?: string;\n};\n\n/**\n * Resolved placement and generation parameters for the CI workflows.\n * See {@link resolveGithubWorkflowsContext}.\n */\nexport type GithubWorkflowsContext = {\n /**\n * Directory the workflow files must be written to. GitHub only triggers\n * workflows stored in `.github/workflows` at the repository root, so this is\n * the git root whenever the project lives inside a git repository.\n */\n workflowsRootDir: string;\n /** Package manager whose commands are baked into the workflows. */\n packageManager: PackageManager;\n /** Generation options forwarded to {@link getGithubWorkflows}. */\n options: GithubWorkflowsOptions;\n};\n\n/**\n * Returns true when the repository root hosts a workspace manifest\n * (a `package.json` `workspaces` field or a `pnpm-workspace.yaml`), meaning a\n * single install at the root covers every package of the monorepo.\n */\nconst hasWorkspaceManifest = (repositoryRootDir: string): boolean => {\n if (existsSync(join(repositoryRootDir, 'pnpm-workspace.yaml'))) {\n return true;\n }\n\n try {\n const packageJsonPath = join(repositoryRootDir, 'package.json');\n if (!existsSync(packageJsonPath)) return false;\n const { workspaces } = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return Boolean(workspaces);\n } catch {\n return false;\n }\n};\n\n/**\n * Resolves where the CI workflows must be written and how their commands must\n * be generated, based on the repository layout around `rootDir` (the Intlayer\n * project being initialized):\n *\n * - Project at the repository root: workflows are written in place. When the\n * repository is a monorepo (workspace manifest, or several Intlayer projects\n * discovered by `listProjects`), the commands go through `intlayer ci` so\n * every project is covered.\n * - Project nested in a repository whose root has a `package.json`\n * (workspace-managed monorepo): workflows are written at the git root —\n * GitHub ignores `.github/workflows` in subdirectories — dependencies are\n * installed at the root with the root's package manager, and the commands go\n * through `intlayer ci` to iterate every Intlayer project.\n * - Project nested in a repository without a root `package.json`: workflows\n * are written at the git root but run inside the project directory\n * (`working-directory`), keeping the project's own package manager.\n */\nexport const resolveGithubWorkflowsContext = async (\n rootDir: string,\n projectPackageManager: PackageManager\n): Promise<GithubWorkflowsContext> => {\n const projectRootDir = resolve(rootDir);\n\n let repositoryRootDir = projectRootDir;\n try {\n const gitRootDir = await getGitRootDir(projectRootDir);\n if (gitRootDir) repositoryRootDir = resolve(gitRootDir);\n } catch {\n // Not a git repository — keep the project root as the workflow root.\n }\n\n // Discover every Intlayer project of the repository. `listProjects` scans\n // for configuration files, so a fresh project whose config is created later\n // in the init flow may not be counted yet — the workspace manifest check\n // below still catches that monorepo case.\n let repositoryProjectCount = 0;\n try {\n const { projectsPath } = await listProjects({\n baseDir: repositoryRootDir,\n });\n repositoryProjectCount = projectsPath.length;\n } catch {\n repositoryProjectCount = 0;\n }\n\n const isNestedProject = repositoryRootDir !== projectRootDir;\n const isWorkspaceRepository = hasWorkspaceManifest(repositoryRootDir);\n const hasRootPackageJson = existsSync(\n join(repositoryRootDir, 'package.json')\n );\n\n if (!isNestedProject) {\n return {\n workflowsRootDir: projectRootDir,\n packageManager: projectPackageManager,\n options: {\n useCiCommand: isWorkspaceRepository || repositoryProjectCount > 1,\n },\n };\n }\n\n if (hasRootPackageJson) {\n return {\n workflowsRootDir: repositoryRootDir,\n packageManager: detectPackageManager(repositoryRootDir),\n options: { useCiCommand: true },\n };\n }\n\n // Nested project without a root manifest: install and run everything inside\n // the project directory itself.\n return {\n workflowsRootDir: repositoryRootDir,\n packageManager: projectPackageManager,\n options: {\n workingDirectory: relative(repositoryRootDir, projectRootDir)\n .split(sep)\n .join('/'),\n },\n };\n};\n\n/**\n * Package-manager-specific snippets used to assemble the CI workflows.\n * - `setupSteps`: YAML steps (already indented for the `steps:` list) that\n * install the package manager and Node.js, including dependency caching.\n * - `installCommand`: command that installs the project dependencies.\n * - `execCommand`: prefix used to run the locally installed `intlayer` binary.\n */\ntype PackageManagerCIConfig = {\n setupSteps: string;\n installCommand: string;\n execCommand: string;\n};\n\n/** Dependency lock file of each package manager, used for cache invalidation. */\nconst LOCK_FILE_BY_PACKAGE_MANAGER: Record<PackageManager, string> = {\n bun: 'bun.lock',\n pnpm: 'pnpm-lock.yaml',\n yarn: 'yarn.lock',\n npm: 'package-lock.json',\n};\n\n/**\n * Returns the package-manager-specific steps and commands used to build the\n * GitHub Actions workflows. Each package manager needs a slightly different\n * setup action and a different way to run the local `intlayer` binary.\n *\n * `workingDirectory` is the repository-relative directory holding the lock\n * file when the project is nested: `actions/setup-node` looks for the lock\n * file at the repository root by default and fails the cache setup otherwise.\n */\nconst getPackageManagerCIConfig = (\n packageManager: PackageManager,\n workingDirectory?: string\n): PackageManagerCIConfig => {\n const setupNodeStep = (cache: PackageManager | undefined): string => {\n const cacheDependencyPath =\n cache && workingDirectory\n ? `\\n cache-dependency-path: ${workingDirectory}/${LOCK_FILE_BY_PACKAGE_MANAGER[cache]}`\n : '';\n\n return ` - name: 🟢 Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: 20${cache ? `\\n cache: ${cache}` : ''}${cacheDependencyPath}`;\n };\n\n switch (packageManager) {\n case 'bun':\n return {\n setupSteps: ` - name: 🥟 Setup Bun\n uses: oven-sh/setup-bun@v2`,\n installCommand: 'bun install --frozen-lockfile',\n execCommand: 'bunx intlayer',\n };\n case 'pnpm':\n return {\n setupSteps: ` - name: 📦 Setup pnpm\n uses: pnpm/action-setup@v4\n${setupNodeStep('pnpm')}`,\n installCommand: 'pnpm install --frozen-lockfile',\n execCommand: 'pnpm exec intlayer',\n };\n case 'yarn':\n return {\n setupSteps: setupNodeStep('yarn'),\n installCommand: 'yarn install --frozen-lockfile',\n execCommand: 'yarn intlayer',\n };\n case 'npm':\n return {\n setupSteps: setupNodeStep('npm'),\n installCommand: 'npm ci',\n execCommand: 'npx intlayer',\n };\n }\n};\n\n/**\n * Renders the `defaults.run.working-directory` block for jobs that must run\n * inside a nested project directory. Empty when the commands run at the\n * repository root.\n */\nconst getWorkingDirectoryBlock = (workingDirectory?: string): string =>\n workingDirectory\n ? `\n defaults:\n run:\n working-directory: ${workingDirectory}`\n : '';\n\n/**\n * Renders the env comment + optional wiring for per-project credentials in\n * monorepo (`intlayer ci`) mode. The `ci` command matches each entry of the\n * `INTLAYER_PROJECT_CREDENTIALS` JSON map to a discovered project path and\n * injects its access keys before running the command in that project.\n */\nconst getMonorepoCredentialsBlock = (useCiCommand?: boolean): string =>\n useCiCommand\n ? `\n #\n # Monorepo — per-project CMS credentials, as a JSON map of project path\n # (relative to the repository root) to access keys, e.g.\n # {\"apps/web\":{\"clientId\":\"...\",\"clientSecret\":\"...\"}}:\n # INTLAYER_PROJECT_CREDENTIALS: \\${{ secrets.INTLAYER_PROJECT_CREDENTIALS }}`\n : '';\n\n/**\n * Builds the `intlayer fill` workflow. Runs on pull requests, regenerates the\n * missing translations for the changed dictionaries (`--git-diff`) using AI,\n * then commits the result back to the PR branch.\n *\n * AI access is required for `fill`. The workflow exposes both options:\n * - a provider API key (`AI_API_KEY` secret), forwarded via CLI flags, or\n * - Intlayer CMS access keys (`INTLAYER_CLIENT_ID` / `INTLAYER_CLIENT_SECRET`).\n */\nconst generateFillWorkflow = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions\n): string => {\n const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(\n packageManager,\n options.workingDirectory\n );\n\n // In monorepo mode `intlayer ci <command>` discovers every Intlayer project\n // of the repository and runs the command inside each of them.\n const intlayerCommand = options.useCiCommand\n ? `${execCommand} ci`\n : execCommand;\n\n return `name: Intlayer Fill\n# Auto-fill missing translations on every pull request.\non:\n pull_request:\n branches:\n - main\n\npermissions:\n contents: write\n pull-requests: write\n\nconcurrency:\n group: intlayer-fill-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n fill:\n runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}\n env:\n # AI access is required to generate translations.\n # Add the secret in: Settings → Secrets and variables → Actions.\n #\n # Option 1 — Use your own AI provider key (forwarded below via CLI flags):\n AI_PROVIDER: openai\n AI_MODEL: gpt-5-mini\n AI_API_KEY: \\${{ secrets.AI_API_KEY }}\n #\n # Option 2 — Use Intlayer CMS access keys instead of your own AI key.\n # Wire them in your intlayer.config and uncomment the lines below:\n # INTLAYER_CLIENT_ID: \\${{ secrets.INTLAYER_CLIENT_ID }}\n # INTLAYER_CLIENT_SECRET: \\${{ secrets.INTLAYER_CLIENT_SECRET }}${getMonorepoCredentialsBlock(options.useCiCommand)}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n with:\n persist-credentials: true # Keep credentials to push back to the PR\n fetch-depth: 0 # Full history so --git-diff can compare refs\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${intlayerCommand} build\n - name: 🤖 Fill missing translations\n # Skip when no AI credentials are configured, so the workflow stays green\n # until an \\`AI_API_KEY\\` (or Intlayer CMS access keys) secret is added.\n if: \\${{ env.AI_API_KEY != '' || env.INTLAYER_CLIENT_ID != '' }}\n run: ${intlayerCommand} fill --git-diff --mode complete --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY\n - name: 📤 Commit and push changes\n run: |\n git config --local user.email \"github-actions[bot]@users.noreply.github.com\"\n git config --local user.name \"github-actions[bot]\"\n if [ -n \"$(git status --porcelain)\" ]; then\n git add .\n git commit -m \"chore(intlayer): fill missing translations [skip ci]\"\n git push origin HEAD:\\${{ github.head_ref }}\n else\n echo \"No missing translations to fill.\"\n fi\n`;\n};\n\n/**\n * Builds the `intlayer test` workflow. Runs on pull requests and fails the\n * check when required locales are missing translations. No AI access needed.\n */\nconst generateTestWorkflow = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions\n): string => {\n const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(\n packageManager,\n options.workingDirectory\n );\n\n // In monorepo mode `intlayer ci <command>` discovers every Intlayer project\n // of the repository and runs the command inside each of them.\n const intlayerCommand = options.useCiCommand\n ? `${execCommand} ci`\n : execCommand;\n\n return `name: Intlayer Test\n# Fail the pull request when required locales are missing translations.\non:\n pull_request:\n branches:\n - main\n\nconcurrency:\n group: intlayer-test-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n test:\n runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${intlayerCommand} build\n - name: 🧪 Test for missing translations\n run: ${intlayerCommand} test\n`;\n};\n\n/** Workflow file path constants, relative to the project root. */\nexport const GITHUB_FILL_WORKFLOW_PATH = '.github/workflows/intlayer-fill.yml';\nexport const GITHUB_TEST_WORKFLOW_PATH = '.github/workflows/intlayer-test.yml';\n\n/**\n * Returns the two Intlayer GitHub Actions workflows (`fill` and `test`),\n * generated with commands matching the detected package manager and the\n * repository layout (see {@link GithubWorkflowsOptions} for the monorepo and\n * nested-project variants).\n */\nexport const getGithubWorkflows = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions = {}\n): GithubWorkflowFile[] => [\n {\n filePath: GITHUB_FILL_WORKFLOW_PATH,\n content: generateFillWorkflow(packageManager, options),\n },\n {\n filePath: GITHUB_TEST_WORKFLOW_PATH,\n content: generateTestWorkflow(packageManager, options),\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/init/utils/jsonParser.ts
4
3
  /**
5
4
  * Helper to parse JSON that may contain comments (tsconfig allows comments)
@@ -1 +1 @@
1
- {"version":3,"file":"jsonParser.cjs","names":[],"sources":["../../../../src/init/utils/jsonParser.ts"],"sourcesContent":["/**\n * Helper to parse JSON that may contain comments (tsconfig allows comments)\n */\nexport const parseJSONWithComments = (jsonString: string) => {\n // First, try parsing as-is (most tsconfig files don't have comments)\n try {\n return JSON.parse(jsonString);\n } catch {\n // If that fails, try stripping comments\n // Note: This simple approach removes comments line by line to avoid\n // matching glob patterns like /* and */ that appear in paths\n }\n\n // Process line by line to safely remove comments\n const lines = jsonString.split('\\n');\n const cleanedLines = lines.map((line) => {\n // Track if we're inside a string\n let inString = false;\n let result = '';\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n const nextChar = line[i + 1];\n\n // Handle string boundaries (accounting for escaped quotes)\n if (char === '\"' && (i === 0 || line[i - 1] !== '\\\\')) {\n inString = !inString;\n result += char;\n continue;\n }\n\n // If we're inside a string, keep the character\n if (inString) {\n result += char;\n continue;\n }\n\n // Check for single-line comment outside of strings\n if (char === '/' && nextChar === '/') {\n // Rest of line is a comment, stop here\n break;\n }\n\n // Check for multi-line comment start (/* ... */)\n // For simplicity, we only handle single-line /* */ comments here\n if (char === '/' && nextChar === '*') {\n const endIndex = line.indexOf('*/', i + 2);\n if (endIndex !== -1) {\n // Skip the comment\n i = endIndex + 1;\n continue;\n }\n }\n\n result += char;\n }\n\n return result;\n });\n\n return JSON.parse(cleanedLines.join('\\n'));\n};\n"],"mappings":";;;;;;AAGA,MAAa,yBAAyB,eAAuB;CAE3D,IAAI;EACF,OAAO,KAAK,MAAM,UAAU;CAC9B,QAAQ,CAIR;CAIA,MAAM,eADQ,WAAW,MAAM,IACN,CAAC,CAAC,KAAK,SAAS;EAEvC,IAAI,WAAW;EACf,IAAI,SAAS;EAEb,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,OAAO,KAAK;GAClB,MAAM,WAAW,KAAK,IAAI;GAG1B,IAAI,SAAS,SAAQ,MAAM,KAAK,KAAK,IAAI,OAAO,OAAO;IACrD,WAAW,CAAC;IACZ,UAAU;IACV;GACF;GAGA,IAAI,UAAU;IACZ,UAAU;IACV;GACF;GAGA,IAAI,SAAS,OAAO,aAAa,KAE/B;GAKF,IAAI,SAAS,OAAO,aAAa,KAAK;IACpC,MAAM,WAAW,KAAK,QAAQ,MAAM,IAAI,CAAC;IACzC,IAAI,aAAa,IAAI;KAEnB,IAAI,WAAW;KACf;IACF;GACF;GAEA,UAAU;EACZ;EAEA,OAAO;CACT,CAAC;CAED,OAAO,KAAK,MAAM,aAAa,KAAK,IAAI,CAAC;AAC3C"}
1
+ {"version":3,"file":"jsonParser.cjs","names":[],"sources":["../../../../src/init/utils/jsonParser.ts"],"sourcesContent":["/**\n * Helper to parse JSON that may contain comments (tsconfig allows comments)\n */\nexport const parseJSONWithComments = (jsonString: string) => {\n // First, try parsing as-is (most tsconfig files don't have comments)\n try {\n return JSON.parse(jsonString);\n } catch {\n // If that fails, try stripping comments\n // Note: This simple approach removes comments line by line to avoid\n // matching glob patterns like /* and */ that appear in paths\n }\n\n // Process line by line to safely remove comments\n const lines = jsonString.split('\\n');\n const cleanedLines = lines.map((line) => {\n // Track if we're inside a string\n let inString = false;\n let result = '';\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n const nextChar = line[i + 1];\n\n // Handle string boundaries (accounting for escaped quotes)\n if (char === '\"' && (i === 0 || line[i - 1] !== '\\\\')) {\n inString = !inString;\n result += char;\n continue;\n }\n\n // If we're inside a string, keep the character\n if (inString) {\n result += char;\n continue;\n }\n\n // Check for single-line comment outside of strings\n if (char === '/' && nextChar === '/') {\n // Rest of line is a comment, stop here\n break;\n }\n\n // Check for multi-line comment start (/* ... */)\n // For simplicity, we only handle single-line /* */ comments here\n if (char === '/' && nextChar === '*') {\n const endIndex = line.indexOf('*/', i + 2);\n if (endIndex !== -1) {\n // Skip the comment\n i = endIndex + 1;\n continue;\n }\n }\n\n result += char;\n }\n\n return result;\n });\n\n return JSON.parse(cleanedLines.join('\\n'));\n};\n"],"mappings":";;;;;AAGA,MAAa,yBAAyB,eAAuB;CAE3D,IAAI;EACF,OAAO,KAAK,MAAM,UAAU;CAC9B,QAAQ,CAIR;CAIA,MAAM,eADQ,WAAW,MAAM,IACN,CAAC,CAAC,KAAK,SAAS;EAEvC,IAAI,WAAW;EACf,IAAI,SAAS;EAEb,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,OAAO,KAAK;GAClB,MAAM,WAAW,KAAK,IAAI;GAG1B,IAAI,SAAS,SAAQ,MAAM,KAAK,KAAK,IAAI,OAAO,OAAO;IACrD,WAAW,CAAC;IACZ,UAAU;IACV;GACF;GAGA,IAAI,UAAU;IACZ,UAAU;IACV;GACF;GAGA,IAAI,SAAS,OAAO,aAAa,KAE/B;GAKF,IAAI,SAAS,OAAO,aAAa,KAAK;IACpC,MAAM,WAAW,KAAK,QAAQ,MAAM,IAAI,CAAC;IACzC,IAAI,aAAa,IAAI;KAEnB,IAAI,WAAW;KACf;IACF;GACF;GAEA,UAAU;EACZ;EAEA,OAAO;CACT,CAAC;CAED,OAAO,KAAK,MAAM,aAAa,KAAK,IAAI,CAAC;AAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"nextCompilerBabel.cjs","names":["exists","ANSIColors","v","x","readFileFromRoot"],"sources":["../../../../src/init/utils/nextCompilerBabel.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport { exists, readFileFromRoot } from './fileSystem';\nimport { installPackages, type PackageManager } from './packageManager';\n\n/**\n * `babel.config.js` wiring the full Intlayer compiler + build-optimization\n * pipeline for Next.js.\n *\n * The four passes run in a fixed order — extract first (so dictionaries exist),\n * optimize last (because it erases the dictionary key the previous passes rely\n * on). `presets: [\"next/babel\"]` is required so Babel keeps compiling JSX/TS\n * the way Next.js does; without it the build breaks.\n */\nexport const NEXT_INTLAYER_BABEL_CONFIG_CONTENT = `const {\n intlayerExtractBabelPlugin,\n intlayerPurgeBabelPlugin,\n intlayerMinifyBabelPlugin,\n intlayerOptimizeBabelPlugin,\n getExtractPluginOptions,\n getPurgePluginOptions,\n getMinifyPluginOptions,\n getOptimizePluginOptions,\n} = require(\"@intlayer/babel\");\n\nmodule.exports = {\n presets: [\"next/babel\"],\n plugins: [\n // Extract: compile .content.ts files → .intlayer/**/*.json\n [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n\n // Purge: remove unused fields from .intlayer/**/*.json\n // (reads intlayer.config.ts build.purge flag)\n [intlayerPurgeBabelPlugin, getPurgePluginOptions()],\n\n // Minify: rename field keys in JSON + source code\n // (reads intlayer.config.ts build.minify flag)\n [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],\n\n // Optimize: rewrite useIntlayer('key') → useDictionary(hash)\n // Must come last because it erases the dictionary key.\n [intlayerOptimizeBabelPlugin, getOptimizePluginOptions()],\n ],\n};\n`;\n\n/** Babel config filenames Next.js picks up, ordered by preference. */\nconst BABEL_CONFIG_CANDIDATES = [\n 'babel.config.js',\n 'babel.config.cjs',\n 'babel.config.mjs',\n 'babel.config.ts',\n 'babel.config.json',\n '.babelrc',\n '.babelrc.js',\n '.babelrc.cjs',\n '.babelrc.json',\n];\n\n/** Dev dependency required to run the Intlayer Babel compiler passes. */\nconst INTLAYER_BABEL_PACKAGE = '@intlayer/babel';\n\n/**\n * Returns the first existing config file from `candidates`, or `undefined` when\n * none are present.\n */\nconst findExistingConfig = async (\n rootDir: string,\n candidates: string[]\n): Promise<string | undefined> => {\n for (const candidate of candidates) {\n if (await exists(rootDir, candidate)) return candidate;\n }\n return undefined;\n};\n\n/**\n * Wires the Intlayer compiler + build-optimization Babel plugins into a Next.js\n * project that already uses Babel.\n *\n * Only acts when a Babel config is detected. A default Next.js project compiles\n * with SWC, where the Intlayer optimize pass is injected automatically by\n * `withIntlayer` once `@intlayer/swc` is installed — no Babel config is needed,\n * so there is nothing to set up here. Writing a `babel.config.js` would in fact\n * be harmful: Next.js falls back from SWC to Babel as soon as one exists, which\n * disables both the project's SWC compiler and the `@intlayer/swc` plugin.\n *\n * When a Babel config is present it:\n *\n * 1. Installs `@intlayer/babel` as a dev dependency (unless already present or\n * `skipInstall` is set).\n * 2. Leaves the existing config untouched and prints the plugins to add, since\n * arbitrary user configs cannot be safely merged.\n *\n * Idempotent: re-running detects the already-wired `@intlayer/babel` import and\n * skips.\n *\n * @param rootDir - Project root directory.\n * @param packageManager - Detected package manager used to install the package.\n * @param allDeps - Combined prod + dev dependencies, used to skip a redundant install.\n * @param skipInstall - When `true`, dependency installation is skipped.\n */\nexport const setupNextCompilerBabelConfig = async ({\n rootDir,\n packageManager,\n allDeps,\n skipInstall,\n}: {\n rootDir: string;\n packageManager: PackageManager;\n allDeps: Record<string, string>;\n skipInstall: boolean;\n}): Promise<void> => {\n const existingBabelConfig = await findExistingConfig(\n rootDir,\n BABEL_CONFIG_CANDIDATES\n );\n\n // Nothing to wire into: the project compiles with SWC, where `withIntlayer`\n // injects the optimize pass automatically once `@intlayer/swc` is installed.\n if (!existingBabelConfig) return;\n\n // INSTALL @intlayer/babel\n if (!skipInstall && !allDeps[INTLAYER_BABEL_PACKAGE]) {\n logger(\n colorize(\n 'Installing the Intlayer Babel compiler dependency...',\n ANSIColors.CYAN\n )\n );\n try {\n installPackages(rootDir, [INTLAYER_BABEL_PACKAGE], packageManager, true);\n logger(\n `${v} Installed: ${colorize(INTLAYER_BABEL_PACKAGE, ANSIColors.MAGENTA)}`\n );\n } catch {\n logger(\n `${x} Failed to install ${INTLAYER_BABEL_PACKAGE}. Please install manually: ${INTLAYER_BABEL_PACKAGE} (dev dependency)`,\n { level: 'warn' }\n );\n }\n }\n\n // EXISTING BABEL CONFIG — never overwrite, print the plugins to add instead.\n const content = await readFileFromRoot(rootDir, existingBabelConfig);\n\n if (content.includes(INTLAYER_BABEL_PACKAGE)) {\n logger(\n `${v} ${colorizePath(existingBabelConfig)} already includes the Intlayer compiler plugins`\n );\n return;\n }\n\n logger(\n `${x} ${colorizePath(existingBabelConfig)} already exists. Add the Intlayer compiler plugins manually:\\n${NEXT_INTLAYER_BABEL_CONFIG_CONTENT}`,\n { level: 'warn' }\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAcA,MAAa,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiClD,MAAM,0BAA0B;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,yBAAyB;;;;;AAM/B,MAAM,qBAAqB,OACzB,SACA,eACgC;CAChC,KAAK,MAAM,aAAa,YACtB,IAAI,MAAMA,qCAAO,SAAS,SAAS,GAAG,OAAO;AAGjD;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,+BAA+B,OAAO,EACjD,SACA,gBACA,SACA,kBAMmB;CACnB,MAAM,sBAAsB,MAAM,mBAChC,SACA,uBACF;CAIA,IAAI,CAAC,qBAAqB;CAG1B,IAAI,CAAC,eAAe,CAAC,QAAQ,yBAAyB;EACpD,0EAEI,wDACAC,wBAAW,IACb,CACF;EACA,IAAI;GACF,kDAAgB,SAAS,CAAC,sBAAsB,GAAG,gBAAgB,IAAI;GACvE,oCACE,GAAGC,0BAAE,oDAAuB,wBAAwBD,wBAAW,OAAO,GACxE;EACF,QAAQ;GACN,oCACE,GAAGE,0BAAE,qBAAqB,uBAAuB,6BAA6B,uBAAuB,oBACrG,EAAE,OAAO,OAAO,CAClB;EACF;CACF;CAKA,KAAI,MAFkBC,+CAAiB,SAAS,mBAAmB,EAExD,CAAC,SAAS,sBAAsB,GAAG;EAC5C,oCACE,GAAGF,0BAAE,6CAAgB,mBAAmB,EAAE,gDAC5C;EACA;CACF;CAEA,oCACE,GAAGC,0BAAE,6CAAgB,mBAAmB,EAAE,gEAAgE,sCAC1G,EAAE,OAAO,OAAO,CAClB;AACF"}
1
+ {"version":3,"file":"nextCompilerBabel.cjs","names":["exists","colorize","ANSIColors","v","x","readFileFromRoot","colorizePath"],"sources":["../../../../src/init/utils/nextCompilerBabel.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport { exists, readFileFromRoot } from './fileSystem';\nimport { installPackages, type PackageManager } from './packageManager';\n\n/**\n * `babel.config.js` wiring the full Intlayer compiler + build-optimization\n * pipeline for Next.js.\n *\n * The four passes run in a fixed order — extract first (so dictionaries exist),\n * optimize last (because it erases the dictionary key the previous passes rely\n * on). `presets: [\"next/babel\"]` is required so Babel keeps compiling JSX/TS\n * the way Next.js does; without it the build breaks.\n */\nexport const NEXT_INTLAYER_BABEL_CONFIG_CONTENT = `const {\n intlayerExtractBabelPlugin,\n intlayerPurgeBabelPlugin,\n intlayerMinifyBabelPlugin,\n intlayerOptimizeBabelPlugin,\n getExtractPluginOptions,\n getPurgePluginOptions,\n getMinifyPluginOptions,\n getOptimizePluginOptions,\n} = require(\"@intlayer/babel\");\n\nmodule.exports = {\n presets: [\"next/babel\"],\n plugins: [\n // Extract: compile .content.ts files → .intlayer/**/*.json\n [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n\n // Purge: remove unused fields from .intlayer/**/*.json\n // (reads intlayer.config.ts build.purge flag)\n [intlayerPurgeBabelPlugin, getPurgePluginOptions()],\n\n // Minify: rename field keys in JSON + source code\n // (reads intlayer.config.ts build.minify flag)\n [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],\n\n // Optimize: rewrite useIntlayer('key') → useDictionary(hash)\n // Must come last because it erases the dictionary key.\n [intlayerOptimizeBabelPlugin, getOptimizePluginOptions()],\n ],\n};\n`;\n\n/** Babel config filenames Next.js picks up, ordered by preference. */\nconst BABEL_CONFIG_CANDIDATES = [\n 'babel.config.js',\n 'babel.config.cjs',\n 'babel.config.mjs',\n 'babel.config.ts',\n 'babel.config.json',\n '.babelrc',\n '.babelrc.js',\n '.babelrc.cjs',\n '.babelrc.json',\n];\n\n/** Dev dependency required to run the Intlayer Babel compiler passes. */\nconst INTLAYER_BABEL_PACKAGE = '@intlayer/babel';\n\n/**\n * Returns the first existing config file from `candidates`, or `undefined` when\n * none are present.\n */\nconst findExistingConfig = async (\n rootDir: string,\n candidates: string[]\n): Promise<string | undefined> => {\n for (const candidate of candidates) {\n if (await exists(rootDir, candidate)) return candidate;\n }\n return undefined;\n};\n\n/**\n * Wires the Intlayer compiler + build-optimization Babel plugins into a Next.js\n * project that already uses Babel.\n *\n * Only acts when a Babel config is detected. A default Next.js project compiles\n * with SWC, where the Intlayer optimize pass is injected automatically by\n * `withIntlayer` once `@intlayer/swc` is installed — no Babel config is needed,\n * so there is nothing to set up here. Writing a `babel.config.js` would in fact\n * be harmful: Next.js falls back from SWC to Babel as soon as one exists, which\n * disables both the project's SWC compiler and the `@intlayer/swc` plugin.\n *\n * When a Babel config is present it:\n *\n * 1. Installs `@intlayer/babel` as a dev dependency (unless already present or\n * `skipInstall` is set).\n * 2. Leaves the existing config untouched and prints the plugins to add, since\n * arbitrary user configs cannot be safely merged.\n *\n * Idempotent: re-running detects the already-wired `@intlayer/babel` import and\n * skips.\n *\n * @param rootDir - Project root directory.\n * @param packageManager - Detected package manager used to install the package.\n * @param allDeps - Combined prod + dev dependencies, used to skip a redundant install.\n * @param skipInstall - When `true`, dependency installation is skipped.\n */\nexport const setupNextCompilerBabelConfig = async ({\n rootDir,\n packageManager,\n allDeps,\n skipInstall,\n}: {\n rootDir: string;\n packageManager: PackageManager;\n allDeps: Record<string, string>;\n skipInstall: boolean;\n}): Promise<void> => {\n const existingBabelConfig = await findExistingConfig(\n rootDir,\n BABEL_CONFIG_CANDIDATES\n );\n\n // Nothing to wire into: the project compiles with SWC, where `withIntlayer`\n // injects the optimize pass automatically once `@intlayer/swc` is installed.\n if (!existingBabelConfig) return;\n\n // INSTALL @intlayer/babel\n if (!skipInstall && !allDeps[INTLAYER_BABEL_PACKAGE]) {\n logger(\n colorize(\n 'Installing the Intlayer Babel compiler dependency...',\n ANSIColors.CYAN\n )\n );\n try {\n installPackages(rootDir, [INTLAYER_BABEL_PACKAGE], packageManager, true);\n logger(\n `${v} Installed: ${colorize(INTLAYER_BABEL_PACKAGE, ANSIColors.MAGENTA)}`\n );\n } catch {\n logger(\n `${x} Failed to install ${INTLAYER_BABEL_PACKAGE}. Please install manually: ${INTLAYER_BABEL_PACKAGE} (dev dependency)`,\n { level: 'warn' }\n );\n }\n }\n\n // EXISTING BABEL CONFIG — never overwrite, print the plugins to add instead.\n const content = await readFileFromRoot(rootDir, existingBabelConfig);\n\n if (content.includes(INTLAYER_BABEL_PACKAGE)) {\n logger(\n `${v} ${colorizePath(existingBabelConfig)} already includes the Intlayer compiler plugins`\n );\n return;\n }\n\n logger(\n `${x} ${colorizePath(existingBabelConfig)} already exists. Add the Intlayer compiler plugins manually:\\n${NEXT_INTLAYER_BABEL_CONFIG_CONTENT}`,\n { level: 'warn' }\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAcA,MAAa,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiClD,MAAM,0BAA0B;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,yBAAyB;;;;;AAM/B,MAAM,qBAAqB,OACzB,SACA,eACgC;CAChC,KAAK,MAAM,aAAa,YACtB,IAAI,MAAMA,qCAAO,SAAS,SAAS,GAAG,OAAO;AAGjD;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,+BAA+B,OAAO,EACjD,SACA,gBACA,SACA,kBAMmB;CACnB,MAAM,sBAAsB,MAAM,mBAChC,SACA,uBACF;CAIA,IAAI,CAAC,qBAAqB;CAG1B,IAAI,CAAC,eAAe,CAAC,QAAQ,yBAAyB;EACpD,wCACEC,kCACE,wDACAC,wBAAW,IACb,CACF;EACA,IAAI;GACF,kDAAgB,SAAS,CAAC,sBAAsB,GAAG,gBAAgB,IAAI;GACvE,oCACE,GAAGC,0BAAE,kBAAcF,kCAAS,wBAAwBC,wBAAW,OAAO,GACxE;EACF,QAAQ;GACN,oCACE,GAAGE,0BAAE,qBAAqB,uBAAuB,6BAA6B,uBAAuB,oBACrG,EAAE,OAAO,OAAO,CAClB;EACF;CACF;CAKA,KAAI,MAFkBC,+CAAiB,SAAS,mBAAmB,EAExD,CAAC,SAAS,sBAAsB,GAAG;EAC5C,oCACE,GAAGF,0BAAE,OAAGG,sCAAa,mBAAmB,EAAE,gDAC5C;EACA;CACF;CAEA,oCACE,GAAGF,0BAAE,OAAGE,sCAAa,mBAAmB,EAAE,gEAAgE,sCAC1G,EAAE,OAAO,OAAO,CAClB;AACF"}
@@ -229,7 +229,8 @@ const detectMissingIntlayerPackages = (allDependencies, options = {}) => {
229
229
  * Throws if the install process exits with a non-zero code.
230
230
  */
231
231
  const installPackages = (rootDir, packages, packageManager, isDev = false) => {
232
- (0, node_child_process.execSync)(buildInstallCommand(packageManager, packages, isDev), {
232
+ const command = buildInstallCommand(packageManager, packages, isDev);
233
+ (0, node_child_process.execSync)(command, {
233
234
  cwd: rootDir,
234
235
  stdio: "inherit"
235
236
  });
@@ -294,7 +295,8 @@ const detectOutdatedIntlayerPackages = (rootDir, dependencies, targetVersion) =>
294
295
  const upgradePackages = (rootDir, packages, packageManager, targetVersion, isDev = false) => {
295
296
  if (packages.length === 0) return;
296
297
  const versionedPackages = packages.map((packageName) => `${packageName}@${targetVersion}`);
297
- (0, node_child_process.execSync)(buildInstallCommand(packageManager, versionedPackages, isDev), {
298
+ const command = buildInstallCommand(packageManager, versionedPackages, isDev);
299
+ (0, node_child_process.execSync)(command, {
298
300
  cwd: rootDir,
299
301
  stdio: "inherit"
300
302
  });
@@ -1 +1 @@
1
- {"version":3,"file":"packageManager.cjs","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { compareVersions } from '@intlayer/config/utils';\n\n/** Package managers supported for dependency installation. */\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Configuration for the syncJSON plugin injected into intlayer.config\n * when a compat i18n library is detected.\n */\nexport type CompatSyncConfig = {\n /**\n * Which sync plugin ingests the catalogs:\n * - `'json'` → `syncJSON` from `@intlayer/sync-json-plugin` (default).\n * - `'po'` → `syncPO` from `@intlayer/sync-po-plugin` (lingui's default\n * format).\n */\n plugin?: 'json' | 'po';\n /**\n * JSON format matching the compat library's conventions. Ignored when\n * `plugin` is `'po'` (PO catalogs are always serialized as gettext).\n */\n format: 'icu' | 'i18next' | 'vue-i18n';\n /**\n * Source path template using ${locale} and ${key} placeholders.\n * Rendered as a template literal in the generated config.\n */\n sourceTemplate: string;\n /**\n * Force `splitKeys: true` in the generated `syncJSON(...)` call so each\n * top-level key of a single per-locale file becomes its own dictionary.\n *\n * Set for libraries whose single `messages/${locale}.json` file groups\n * namespaces by its first-level keys (`next-intl` / `use-intl`, where\n * `useTranslations('Hero')` resolves to the `Hero` dictionary). Left\n * undefined for libraries whose top-level keys are plain message keys\n * (e.g. `i18next`, `react-intl`); for those, syncJSON's auto-detection\n * (split only when the source has no `${key}` segment) stays in control.\n *\n * Only meaningful for flat templates (no `${key}` segment); it is dropped\n * automatically when the resolved template addresses one namespace per file.\n */\n splitKeys?: boolean;\n};\n\n/**\n * Configuration for injecting a compat vite plugin into vite.config.\n * The plugin replaces the generic `intlayer` plugin for libraries that\n * require alias injection (e.g. `vue-i18n` → `@intlayer/vue-i18n`).\n */\nexport type CompatVitePluginConfig = {\n /** Exported function name from the plugin package, e.g. `'vueI18nVitePlugin'`. */\n pluginFunctionName: string;\n /** Import path for the plugin package, e.g. `'@intlayer/vue-i18n/plugin'`. */\n pluginPackageSource: string;\n /**\n * Set when the compat plugin is a drop-in replacement for an i18n library's\n * own Vite plugin (e.g. lingui ships `@lingui/vite-plugin`). When the original\n * import is present, init rewrites only that import's module source to\n * `pluginPackageSource` — keeping the binding and its call site — instead of\n * injecting a second import and appending another plugin to the array.\n */\n replacesVitePlugin?: {\n /** Imported binding to keep, e.g. `'lingui'`. */\n importName: string;\n /** Original package source to rewrite, e.g. `'@lingui/vite-plugin'`. */\n fromPackageSource: string;\n };\n};\n\n/** Result of analyzing project dependencies for intlayer package gaps. */\nexport type IntlayerPackageAnalysis = {\n /** Intlayer packages that are referenced but not yet installed. */\n packagesToInstall: string[];\n /** Intlayer dev packages that are referenced but not yet installed. */\n devPackagesToInstall: string[];\n /**\n * syncJSON plugin configuration to inject when a compat i18n library is\n * detected. Undefined when no compat library is present or format is not\n * yet implemented.\n */\n compatSyncConfig: CompatSyncConfig | undefined;\n /**\n * Vite config plugin to inject when a vite-based compat library is\n * detected. Undefined for Next.js/Nuxt-only compat libs or when no compat\n * library requires alias injection.\n */\n compatVitePluginConfig: CompatVitePluginConfig | undefined;\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root. Falls back to npm when no lock file is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager => {\n if (\n existsSync(join(rootDir, 'bun.lock')) ||\n existsSync(join(rootDir, 'bun.lockb'))\n ) {\n return 'bun';\n }\n if (existsSync(join(rootDir, 'pnpm-lock.yaml'))) {\n return 'pnpm';\n }\n if (existsSync(join(rootDir, 'yarn.lock'))) {\n return 'yarn';\n }\n return 'npm';\n};\n\n/**\n * Returns the install command for the given package manager and package list.\n */\nconst buildInstallCommand = (\n packageManager: PackageManager,\n packages: string[],\n isDev: boolean = false\n): string => {\n const packageList = packages.join(' ');\n switch (packageManager) {\n case 'bun':\n return `bun add ${isDev ? '-d ' : ''}${packageList}`;\n case 'pnpm':\n return `pnpm add ${isDev ? '-D ' : ''}${packageList}`;\n case 'yarn':\n return `yarn add ${isDev ? '-D ' : ''}${packageList}`;\n case 'npm':\n return `npm install ${isDev ? '-D ' : ''}${packageList}`;\n }\n};\n\n/**\n * Analyzes existing project dependencies to determine which intlayer packages\n * are missing and what syncJSON configuration to inject when compat i18n\n * libraries are present.\n */\n/** Extra signals (from a filesystem scan) that refine compat detection. */\nexport type DetectMissingPackagesOptions = {\n /**\n * Catalog format detected for a lingui project (`'po'` or `'json'`), or\n * `null`/undefined when none was found. Decides which sync plugin + dev\n * dependency the lingui compat setup uses.\n */\n linguiCatalogFormat?: 'po' | 'json' | null;\n /**\n * Extra package names injected by the interactive init prompt when the user\n * selects a compat i18n library that is not yet in `package.json`.\n * These are merged with the real dependency map before running detection so\n * the correct sync plugin and compat adapter are scheduled for installation.\n */\n hintDependencies?: Record<string, string>;\n};\n\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>,\n options: DetectMissingPackagesOptions = {}\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n let compatSyncConfig: CompatSyncConfig | undefined;\n let compatVitePluginConfig: CompatVitePluginConfig | undefined;\n\n // Merge hint deps supplied by the interactive init prompt so that compat\n // libraries the user declared (but hasn't installed yet) are treated the same\n // as pre-existing deps when building the install and config lists.\n const effectiveDependencies: Record<string, string> = {\n ...allDependencies,\n ...(options.hintDependencies ?? {}),\n };\n\n const isInstalled = (packageName: string): boolean =>\n Boolean(effectiveDependencies[packageName]);\n\n const addIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n packagesToInstall.push(packageName);\n }\n };\n\n const addDevIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n devPackagesToInstall.push(packageName);\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isInstalled('react')) {\n addIfMissing('react-intlayer');\n }\n\n // React Native / Expo — the Metro plugin lives in react-native-intlayer,\n // installed as a dev dependency (it is only used by the bundler).\n if (isInstalled('react-native') || isInstalled('expo')) {\n addDevIfMissing('react-native-intlayer');\n }\n\n if (isInstalled('svelte')) {\n addIfMissing('svelte-intlayer');\n }\n\n if (isInstalled('solid-js')) {\n addIfMissing('solid-intlayer');\n }\n\n if (isInstalled('@angular/core')) {\n addIfMissing('angular-intlayer');\n }\n\n if (isInstalled('vue')) {\n addIfMissing('vue-intlayer');\n }\n\n if (isInstalled('vite')) {\n addIfMissing('vite-intlayer');\n }\n\n // -------------------------------------------------------------------------\n // Compat adapters for existing i18n libraries.\n //\n // Detection order matters: more specific libraries are checked first so that\n // `compatSyncConfig ??=` and `compatVitePluginConfig ??=` capture the most\n // relevant match. Libraries that only affect the Next.js or Nuxt config do\n // not set `compatVitePluginConfig` (handled separately in init/index.ts).\n // Libraries whose JSON format is not yet supported leave `compatSyncConfig`\n // undefined so no syncJSON plugin is injected.\n // -------------------------------------------------------------------------\n\n // next-intl — next.js only, ICU format. Default layout is a single file per\n // locale (`messages/${locale}.json`) whose top-level keys are namespaces;\n // syncJSON `splitKeys` auto-detection (no `${key}` segment) turns each\n // top-level key into its own dictionary. The exact path is refined from\n // `i18n/request.ts` in init/index.ts when present.\n if (isInstalled('next-intl') || isInstalled('@intlayer/next-intl')) {\n addIfMissing('@intlayer/next-intl');\n addIfMissing('next-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // next-intl groups namespaces by the first-level keys of one file.\n splitKeys: true,\n };\n // next config handled via updateNextConfigForNextIntl in init/index.ts\n }\n\n // next-i18next — next.js only, i18next JSON format\n if (isInstalled('next-i18next') || isInstalled('@intlayer/next-i18next')) {\n addIfMissing('@intlayer/next-i18next');\n addIfMissing('next-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextI18next in init/index.ts\n }\n\n // next-translate — next.js only, i18next-style flat-namespace JSON\n if (\n isInstalled('next-translate') ||\n isInstalled('@intlayer/next-translate')\n ) {\n addIfMissing('@intlayer/next-translate');\n addIfMissing('next-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextTranslate in init/index.ts\n }\n\n // i18next — vite alias injection (`i18next` → `@intlayer/i18next`) so existing\n // `import … from 'i18next'` is served by Intlayer without touching call sites.\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n addIfMissing('@intlayer/i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // When react-i18next is also present, its wrapper plugin aliases both\n // `react-i18next` and `i18next`, so it must win — only inject the bare\n // i18next plugin when no React wrapper is installed.\n if (\n !isInstalled('react-i18next') &&\n !isInstalled('@intlayer/react-i18next')\n ) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nextVitePlugin',\n pluginPackageSource: '@intlayer/i18next/plugin',\n };\n }\n }\n\n // react-i18next — vite alias injection (`react-i18next` → `@intlayer/react-i18next`\n // and `i18next` → `@intlayer/i18next`) so components keep importing from\n // `react-i18next` unchanged.\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n addIfMissing('@intlayer/react-i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactI18nextVitePlugin',\n pluginPackageSource: '@intlayer/react-i18next/plugin',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n addIfMissing('@intlayer/vue-i18n');\n addIfMissing('vue-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'vueI18nVitePlugin',\n pluginPackageSource: '@intlayer/vue-i18n/plugin',\n };\n }\n\n // use-intl — framework-agnostic React core of next-intl; vite alias\n // injection required, ICU format. Commonly a single `messages/${locale}.json`\n // file whose top-level keys are namespaces, handled by syncJSON `splitKeys`\n // auto-detection (no `${key}` segment in the source template).\n if (isInstalled('use-intl') || isInstalled('@intlayer/use-intl')) {\n addIfMissing('@intlayer/use-intl');\n addIfMissing('use-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // use-intl (the core of next-intl) uses the same single-file namespace model.\n splitKeys: true,\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'useIntlVitePlugin',\n pluginPackageSource: '@intlayer/use-intl/plugin',\n };\n }\n\n // react-intl — vite alias injection required, ICU format\n if (isInstalled('react-intl') || isInstalled('@intlayer/react-intl')) {\n addIfMissing('@intlayer/react-intl');\n addIfMissing('react-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './src/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactIntlVitePlugin',\n pluginPackageSource: '@intlayer/react-intl/plugin',\n };\n }\n\n // @ngneat/transloco — vite alias injection required\n // @todo syncJSON format not yet implemented for transloco\n if (isInstalled('@ngneat/transloco') || isInstalled('@intlayer/transloco')) {\n addIfMissing('@intlayer/transloco');\n addIfMissing('@ngneat/transloco');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n addIfMissing('@intlayer/svelte-i18n');\n addIfMissing('svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\n }\n\n // node-polyglot — vite alias injection required\n // @todo syncJSON format not yet implemented for polyglot\n if (isInstalled('node-polyglot') || isInstalled('@intlayer/polyglot')) {\n addIfMissing('@intlayer/polyglot');\n addIfMissing('node-polyglot');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\n }\n\n // @nuxtjs/i18n — nuxt module (no vite plugin), vue-i18n JSON format\n if (isInstalled('@nuxtjs/i18n') || isInstalled('@intlayer/nuxtjs-i18n')) {\n addIfMissing('@intlayer/nuxtjs-i18n');\n addIfMissing('@nuxtjs/i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // nuxt config handled via updateNuxtConfigForNuxtjsI18n in init/index.ts\n }\n\n // @ngx-translate/core — vite alias injection required, flat JSON (i18next)\n if (\n isInstalled('@ngx-translate/core') ||\n isInstalled('@intlayer/ngx-translate')\n ) {\n addIfMissing('@intlayer/ngx-translate');\n addIfMissing('@ngx-translate/core');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n\n // @lingui/core — vite alias injection required.\n // lingui keeps one catalog file per locale (default name `messages`), as\n // `.po` (its default) or `.json`. The catalog filename is captured by the\n // `${key}` segment so the produced dictionary key is `messages`, matching the\n // fixed `messages` namespace the lingui compat runtime reads from.\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n addIfMissing('@intlayer/lingui');\n addIfMissing('@lingui/core');\n\n const linguiUsesPo = options.linguiCatalogFormat === 'po';\n compatSyncConfig ??= linguiUsesPo\n ? {\n plugin: 'po',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.po',\n }\n : {\n plugin: 'json',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n\n compatVitePluginConfig ??= {\n // `@intlayer/lingui/plugin` exports `lingui` as a drop-in replacement for\n // `@lingui/vite-plugin`, so a fresh project gets `lingui()` injected and a\n // project already using `@lingui/vite-plugin` only has its import source\n // rewritten (see `replacesVitePlugin`).\n pluginFunctionName: 'lingui',\n pluginPackageSource: '@intlayer/lingui/plugin',\n replacesVitePlugin: {\n importName: 'lingui',\n fromPackageSource: '@lingui/vite-plugin',\n },\n };\n }\n\n // i18n-js — vite alias injection required\n // @todo syncJSON format not yet implemented for i18n-js\n if (isInstalled('i18n-js') || isInstalled('@intlayer/i18n-js')) {\n addIfMissing('@intlayer/i18n-js');\n addIfMissing('i18n-js');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n\n if (compatSyncConfig) {\n addDevIfMissing(\n compatSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin'\n );\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n compatSyncConfig,\n compatVitePluginConfig,\n };\n};\n\n/**\n * Runs the package install command synchronously.\n * Throws if the install process exits with a non-zero code.\n */\nexport const installPackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n isDev: boolean = false\n): void => {\n const command = buildInstallCommand(packageManager, packages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n\n/**\n * Determines whether a dependency name belongs to the Intlayer ecosystem.\n *\n * Matches the core `intlayer` package, every scoped `@intlayer/*` package\n * (including compat adapters such as `@intlayer/next-intl`) and the framework\n * runtime integrations that follow the `<framework>-intlayer` convention\n * (e.g. `next-intlayer`, `react-intlayer`, `express-intlayer`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n /-intlayer$/.test(packageName);\n\n/**\n * Reduces a semver range or full version to its `major.minor.patch` core,\n * stripping range prefixes (`^`, `~`), pre-release identifiers and build\n * metadata. Returns `null` when no `major.minor.patch` can be extracted.\n *\n * @example normalizeVersion('^9.0.0-canary.3') // '9.0.0'\n */\nexport const normalizeVersion = (version?: string): string | null => {\n if (!version || typeof version !== 'string') return null;\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Reads the installed version of a package from its `package.json` inside the\n * project's `node_modules`. Returns `null` when the package is not installed or\n * its manifest cannot be read.\n */\nexport const getInstalledPackageVersion = (\n rootDir: string,\n packageName: string\n): string | null => {\n try {\n const manifestPath = join(\n rootDir,\n 'node_modules',\n packageName,\n 'package.json'\n );\n if (!existsSync(manifestPath)) return null;\n const { version } = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n return typeof version === 'string' ? version : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Returns the Intlayer packages from `dependencies` whose installed version is\n * behind `targetVersion` (compared on `major.minor.patch`). Packages that are\n * not installed yet are ignored — those are handled by\n * {@link detectMissingIntlayerPackages}.\n */\nexport const detectOutdatedIntlayerPackages = (\n rootDir: string,\n dependencies: Record<string, string>,\n targetVersion: string\n): string[] => {\n const normalizedTarget = normalizeVersion(targetVersion);\n if (!normalizedTarget) return [];\n\n return Object.keys(dependencies)\n .filter(isIntlayerPackageName)\n .filter((packageName) => {\n const installedVersion = getInstalledPackageVersion(rootDir, packageName);\n const normalizedInstalled = normalizeVersion(\n installedVersion ?? undefined\n );\n if (!normalizedInstalled) return false;\n return compareVersions(normalizedInstalled, '<', normalizedTarget);\n });\n};\n\n/**\n * Upgrades the given packages to `targetVersion` synchronously, preserving the\n * dependency type via the `isDev` flag. Throws if the install process exits\n * with a non-zero code.\n */\nexport const upgradePackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n targetVersion: string,\n isDev: boolean = false\n): void => {\n if (packages.length === 0) return;\n const versionedPackages = packages.map(\n (packageName) => `${packageName}@${targetVersion}`\n );\n const command = buildInstallCommand(packageManager, versionedPackages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"packageManager.cjs","names":["existsSync","join","readFileSync","compareVersions"],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { compareVersions } from '@intlayer/config/utils';\n\n/** Package managers supported for dependency installation. */\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Configuration for the syncJSON plugin injected into intlayer.config\n * when a compat i18n library is detected.\n */\nexport type CompatSyncConfig = {\n /**\n * Which sync plugin ingests the catalogs:\n * - `'json'` → `syncJSON` from `@intlayer/sync-json-plugin` (default).\n * - `'po'` → `syncPO` from `@intlayer/sync-po-plugin` (lingui's default\n * format).\n */\n plugin?: 'json' | 'po';\n /**\n * JSON format matching the compat library's conventions. Ignored when\n * `plugin` is `'po'` (PO catalogs are always serialized as gettext).\n */\n format: 'icu' | 'i18next' | 'vue-i18n';\n /**\n * Source path template using ${locale} and ${key} placeholders.\n * Rendered as a template literal in the generated config.\n */\n sourceTemplate: string;\n /**\n * Force `splitKeys: true` in the generated `syncJSON(...)` call so each\n * top-level key of a single per-locale file becomes its own dictionary.\n *\n * Set for libraries whose single `messages/${locale}.json` file groups\n * namespaces by its first-level keys (`next-intl` / `use-intl`, where\n * `useTranslations('Hero')` resolves to the `Hero` dictionary). Left\n * undefined for libraries whose top-level keys are plain message keys\n * (e.g. `i18next`, `react-intl`); for those, syncJSON's auto-detection\n * (split only when the source has no `${key}` segment) stays in control.\n *\n * Only meaningful for flat templates (no `${key}` segment); it is dropped\n * automatically when the resolved template addresses one namespace per file.\n */\n splitKeys?: boolean;\n};\n\n/**\n * Configuration for injecting a compat vite plugin into vite.config.\n * The plugin replaces the generic `intlayer` plugin for libraries that\n * require alias injection (e.g. `vue-i18n` → `@intlayer/vue-i18n`).\n */\nexport type CompatVitePluginConfig = {\n /** Exported function name from the plugin package, e.g. `'vueI18nVitePlugin'`. */\n pluginFunctionName: string;\n /** Import path for the plugin package, e.g. `'@intlayer/vue-i18n/plugin'`. */\n pluginPackageSource: string;\n /**\n * Set when the compat plugin is a drop-in replacement for an i18n library's\n * own Vite plugin (e.g. lingui ships `@lingui/vite-plugin`). When the original\n * import is present, init rewrites only that import's module source to\n * `pluginPackageSource` — keeping the binding and its call site — instead of\n * injecting a second import and appending another plugin to the array.\n */\n replacesVitePlugin?: {\n /** Imported binding to keep, e.g. `'lingui'`. */\n importName: string;\n /** Original package source to rewrite, e.g. `'@lingui/vite-plugin'`. */\n fromPackageSource: string;\n };\n};\n\n/** Result of analyzing project dependencies for intlayer package gaps. */\nexport type IntlayerPackageAnalysis = {\n /** Intlayer packages that are referenced but not yet installed. */\n packagesToInstall: string[];\n /** Intlayer dev packages that are referenced but not yet installed. */\n devPackagesToInstall: string[];\n /**\n * syncJSON plugin configuration to inject when a compat i18n library is\n * detected. Undefined when no compat library is present or format is not\n * yet implemented.\n */\n compatSyncConfig: CompatSyncConfig | undefined;\n /**\n * Vite config plugin to inject when a vite-based compat library is\n * detected. Undefined for Next.js/Nuxt-only compat libs or when no compat\n * library requires alias injection.\n */\n compatVitePluginConfig: CompatVitePluginConfig | undefined;\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root. Falls back to npm when no lock file is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager => {\n if (\n existsSync(join(rootDir, 'bun.lock')) ||\n existsSync(join(rootDir, 'bun.lockb'))\n ) {\n return 'bun';\n }\n if (existsSync(join(rootDir, 'pnpm-lock.yaml'))) {\n return 'pnpm';\n }\n if (existsSync(join(rootDir, 'yarn.lock'))) {\n return 'yarn';\n }\n return 'npm';\n};\n\n/**\n * Returns the install command for the given package manager and package list.\n */\nconst buildInstallCommand = (\n packageManager: PackageManager,\n packages: string[],\n isDev: boolean = false\n): string => {\n const packageList = packages.join(' ');\n switch (packageManager) {\n case 'bun':\n return `bun add ${isDev ? '-d ' : ''}${packageList}`;\n case 'pnpm':\n return `pnpm add ${isDev ? '-D ' : ''}${packageList}`;\n case 'yarn':\n return `yarn add ${isDev ? '-D ' : ''}${packageList}`;\n case 'npm':\n return `npm install ${isDev ? '-D ' : ''}${packageList}`;\n }\n};\n\n/**\n * Analyzes existing project dependencies to determine which intlayer packages\n * are missing and what syncJSON configuration to inject when compat i18n\n * libraries are present.\n */\n/** Extra signals (from a filesystem scan) that refine compat detection. */\nexport type DetectMissingPackagesOptions = {\n /**\n * Catalog format detected for a lingui project (`'po'` or `'json'`), or\n * `null`/undefined when none was found. Decides which sync plugin + dev\n * dependency the lingui compat setup uses.\n */\n linguiCatalogFormat?: 'po' | 'json' | null;\n /**\n * Extra package names injected by the interactive init prompt when the user\n * selects a compat i18n library that is not yet in `package.json`.\n * These are merged with the real dependency map before running detection so\n * the correct sync plugin and compat adapter are scheduled for installation.\n */\n hintDependencies?: Record<string, string>;\n};\n\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>,\n options: DetectMissingPackagesOptions = {}\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n let compatSyncConfig: CompatSyncConfig | undefined;\n let compatVitePluginConfig: CompatVitePluginConfig | undefined;\n\n // Merge hint deps supplied by the interactive init prompt so that compat\n // libraries the user declared (but hasn't installed yet) are treated the same\n // as pre-existing deps when building the install and config lists.\n const effectiveDependencies: Record<string, string> = {\n ...allDependencies,\n ...(options.hintDependencies ?? {}),\n };\n\n const isInstalled = (packageName: string): boolean =>\n Boolean(effectiveDependencies[packageName]);\n\n const addIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n packagesToInstall.push(packageName);\n }\n };\n\n const addDevIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n devPackagesToInstall.push(packageName);\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isInstalled('react')) {\n addIfMissing('react-intlayer');\n }\n\n // React Native / Expo — the Metro plugin lives in react-native-intlayer,\n // installed as a dev dependency (it is only used by the bundler).\n if (isInstalled('react-native') || isInstalled('expo')) {\n addDevIfMissing('react-native-intlayer');\n }\n\n if (isInstalled('svelte')) {\n addIfMissing('svelte-intlayer');\n }\n\n if (isInstalled('solid-js')) {\n addIfMissing('solid-intlayer');\n }\n\n if (isInstalled('@angular/core')) {\n addIfMissing('angular-intlayer');\n }\n\n if (isInstalled('vue')) {\n addIfMissing('vue-intlayer');\n }\n\n if (isInstalled('vite')) {\n addIfMissing('vite-intlayer');\n }\n\n // -------------------------------------------------------------------------\n // Compat adapters for existing i18n libraries.\n //\n // Detection order matters: more specific libraries are checked first so that\n // `compatSyncConfig ??=` and `compatVitePluginConfig ??=` capture the most\n // relevant match. Libraries that only affect the Next.js or Nuxt config do\n // not set `compatVitePluginConfig` (handled separately in init/index.ts).\n // Libraries whose JSON format is not yet supported leave `compatSyncConfig`\n // undefined so no syncJSON plugin is injected.\n // -------------------------------------------------------------------------\n\n // next-intl — next.js only, ICU format. Default layout is a single file per\n // locale (`messages/${locale}.json`) whose top-level keys are namespaces;\n // syncJSON `splitKeys` auto-detection (no `${key}` segment) turns each\n // top-level key into its own dictionary. The exact path is refined from\n // `i18n/request.ts` in init/index.ts when present.\n if (isInstalled('next-intl') || isInstalled('@intlayer/next-intl')) {\n addIfMissing('@intlayer/next-intl');\n addIfMissing('next-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // next-intl groups namespaces by the first-level keys of one file.\n splitKeys: true,\n };\n // next config handled via updateNextConfigForNextIntl in init/index.ts\n }\n\n // next-i18next — next.js only, i18next JSON format\n if (isInstalled('next-i18next') || isInstalled('@intlayer/next-i18next')) {\n addIfMissing('@intlayer/next-i18next');\n addIfMissing('next-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextI18next in init/index.ts\n }\n\n // next-translate — next.js only, i18next-style flat-namespace JSON\n if (\n isInstalled('next-translate') ||\n isInstalled('@intlayer/next-translate')\n ) {\n addIfMissing('@intlayer/next-translate');\n addIfMissing('next-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextTranslate in init/index.ts\n }\n\n // i18next — vite alias injection (`i18next` → `@intlayer/i18next`) so existing\n // `import … from 'i18next'` is served by Intlayer without touching call sites.\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n addIfMissing('@intlayer/i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // When react-i18next is also present, its wrapper plugin aliases both\n // `react-i18next` and `i18next`, so it must win — only inject the bare\n // i18next plugin when no React wrapper is installed.\n if (\n !isInstalled('react-i18next') &&\n !isInstalled('@intlayer/react-i18next')\n ) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nextVitePlugin',\n pluginPackageSource: '@intlayer/i18next/plugin',\n };\n }\n }\n\n // react-i18next — vite alias injection (`react-i18next` → `@intlayer/react-i18next`\n // and `i18next` → `@intlayer/i18next`) so components keep importing from\n // `react-i18next` unchanged.\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n addIfMissing('@intlayer/react-i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactI18nextVitePlugin',\n pluginPackageSource: '@intlayer/react-i18next/plugin',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n addIfMissing('@intlayer/vue-i18n');\n addIfMissing('vue-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'vueI18nVitePlugin',\n pluginPackageSource: '@intlayer/vue-i18n/plugin',\n };\n }\n\n // use-intl — framework-agnostic React core of next-intl; vite alias\n // injection required, ICU format. Commonly a single `messages/${locale}.json`\n // file whose top-level keys are namespaces, handled by syncJSON `splitKeys`\n // auto-detection (no `${key}` segment in the source template).\n if (isInstalled('use-intl') || isInstalled('@intlayer/use-intl')) {\n addIfMissing('@intlayer/use-intl');\n addIfMissing('use-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // use-intl (the core of next-intl) uses the same single-file namespace model.\n splitKeys: true,\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'useIntlVitePlugin',\n pluginPackageSource: '@intlayer/use-intl/plugin',\n };\n }\n\n // react-intl — vite alias injection required, ICU format\n if (isInstalled('react-intl') || isInstalled('@intlayer/react-intl')) {\n addIfMissing('@intlayer/react-intl');\n addIfMissing('react-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './src/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactIntlVitePlugin',\n pluginPackageSource: '@intlayer/react-intl/plugin',\n };\n }\n\n // @ngneat/transloco — vite alias injection required\n // @todo syncJSON format not yet implemented for transloco\n if (isInstalled('@ngneat/transloco') || isInstalled('@intlayer/transloco')) {\n addIfMissing('@intlayer/transloco');\n addIfMissing('@ngneat/transloco');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n addIfMissing('@intlayer/svelte-i18n');\n addIfMissing('svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\n }\n\n // node-polyglot — vite alias injection required\n // @todo syncJSON format not yet implemented for polyglot\n if (isInstalled('node-polyglot') || isInstalled('@intlayer/polyglot')) {\n addIfMissing('@intlayer/polyglot');\n addIfMissing('node-polyglot');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\n }\n\n // @nuxtjs/i18n — nuxt module (no vite plugin), vue-i18n JSON format\n if (isInstalled('@nuxtjs/i18n') || isInstalled('@intlayer/nuxtjs-i18n')) {\n addIfMissing('@intlayer/nuxtjs-i18n');\n addIfMissing('@nuxtjs/i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // nuxt config handled via updateNuxtConfigForNuxtjsI18n in init/index.ts\n }\n\n // @ngx-translate/core — vite alias injection required, flat JSON (i18next)\n if (\n isInstalled('@ngx-translate/core') ||\n isInstalled('@intlayer/ngx-translate')\n ) {\n addIfMissing('@intlayer/ngx-translate');\n addIfMissing('@ngx-translate/core');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n\n // @lingui/core — vite alias injection required.\n // lingui keeps one catalog file per locale (default name `messages`), as\n // `.po` (its default) or `.json`. The catalog filename is captured by the\n // `${key}` segment so the produced dictionary key is `messages`, matching the\n // fixed `messages` namespace the lingui compat runtime reads from.\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n addIfMissing('@intlayer/lingui');\n addIfMissing('@lingui/core');\n\n const linguiUsesPo = options.linguiCatalogFormat === 'po';\n compatSyncConfig ??= linguiUsesPo\n ? {\n plugin: 'po',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.po',\n }\n : {\n plugin: 'json',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n\n compatVitePluginConfig ??= {\n // `@intlayer/lingui/plugin` exports `lingui` as a drop-in replacement for\n // `@lingui/vite-plugin`, so a fresh project gets `lingui()` injected and a\n // project already using `@lingui/vite-plugin` only has its import source\n // rewritten (see `replacesVitePlugin`).\n pluginFunctionName: 'lingui',\n pluginPackageSource: '@intlayer/lingui/plugin',\n replacesVitePlugin: {\n importName: 'lingui',\n fromPackageSource: '@lingui/vite-plugin',\n },\n };\n }\n\n // i18n-js — vite alias injection required\n // @todo syncJSON format not yet implemented for i18n-js\n if (isInstalled('i18n-js') || isInstalled('@intlayer/i18n-js')) {\n addIfMissing('@intlayer/i18n-js');\n addIfMissing('i18n-js');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n\n if (compatSyncConfig) {\n addDevIfMissing(\n compatSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin'\n );\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n compatSyncConfig,\n compatVitePluginConfig,\n };\n};\n\n/**\n * Runs the package install command synchronously.\n * Throws if the install process exits with a non-zero code.\n */\nexport const installPackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n isDev: boolean = false\n): void => {\n const command = buildInstallCommand(packageManager, packages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n\n/**\n * Determines whether a dependency name belongs to the Intlayer ecosystem.\n *\n * Matches the core `intlayer` package, every scoped `@intlayer/*` package\n * (including compat adapters such as `@intlayer/next-intl`) and the framework\n * runtime integrations that follow the `<framework>-intlayer` convention\n * (e.g. `next-intlayer`, `react-intlayer`, `express-intlayer`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n /-intlayer$/.test(packageName);\n\n/**\n * Reduces a semver range or full version to its `major.minor.patch` core,\n * stripping range prefixes (`^`, `~`), pre-release identifiers and build\n * metadata. Returns `null` when no `major.minor.patch` can be extracted.\n *\n * @example normalizeVersion('^9.0.0-canary.3') // '9.0.0'\n */\nexport const normalizeVersion = (version?: string): string | null => {\n if (!version || typeof version !== 'string') return null;\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Reads the installed version of a package from its `package.json` inside the\n * project's `node_modules`. Returns `null` when the package is not installed or\n * its manifest cannot be read.\n */\nexport const getInstalledPackageVersion = (\n rootDir: string,\n packageName: string\n): string | null => {\n try {\n const manifestPath = join(\n rootDir,\n 'node_modules',\n packageName,\n 'package.json'\n );\n if (!existsSync(manifestPath)) return null;\n const { version } = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n return typeof version === 'string' ? version : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Returns the Intlayer packages from `dependencies` whose installed version is\n * behind `targetVersion` (compared on `major.minor.patch`). Packages that are\n * not installed yet are ignored — those are handled by\n * {@link detectMissingIntlayerPackages}.\n */\nexport const detectOutdatedIntlayerPackages = (\n rootDir: string,\n dependencies: Record<string, string>,\n targetVersion: string\n): string[] => {\n const normalizedTarget = normalizeVersion(targetVersion);\n if (!normalizedTarget) return [];\n\n return Object.keys(dependencies)\n .filter(isIntlayerPackageName)\n .filter((packageName) => {\n const installedVersion = getInstalledPackageVersion(rootDir, packageName);\n const normalizedInstalled = normalizeVersion(\n installedVersion ?? undefined\n );\n if (!normalizedInstalled) return false;\n return compareVersions(normalizedInstalled, '<', normalizedTarget);\n });\n};\n\n/**\n * Upgrades the given packages to `targetVersion` synchronously, preserving the\n * dependency type via the `isDev` flag. Throws if the install process exits\n * with a non-zero code.\n */\nexport const upgradePackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n targetVersion: string,\n isDev: boolean = false\n): void => {\n if (packages.length === 0) return;\n const versionedPackages = packages.map(\n (packageName) => `${packageName}@${targetVersion}`\n );\n const command = buildInstallCommand(packageManager, versionedPackages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tsConfig.cjs","names":[],"sources":["../../../../src/init/utils/tsConfig.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises';\n\n/**\n * Helper to find all tsconfig files (tsconfig.json, tsconfig.*.json)\n */\nexport const findTsConfigFiles = async (rootDir: string): Promise<string[]> => {\n try {\n const files = await readdir(rootDir);\n\n return files.filter(\n (file) => file === 'tsconfig.json' || /^tsconfig\\..+\\.json$/.test(file)\n );\n } catch {\n return [];\n }\n};\n"],"mappings":";;;;;;;AAKA,MAAa,oBAAoB,OAAO,YAAuC;CAC7E,IAAI;EAGF,QAAO,oCAFqB,OAAO,EAEvB,CAAC,QACV,SAAS,SAAS,mBAAmB,uBAAuB,KAAK,IAAI,CACxE;CACF,QAAQ;EACN,OAAO,CAAC;CACV;AACF"}
1
+ {"version":3,"file":"tsConfig.cjs","names":["readdir"],"sources":["../../../../src/init/utils/tsConfig.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises';\n\n/**\n * Helper to find all tsconfig files (tsconfig.json, tsconfig.*.json)\n */\nexport const findTsConfigFiles = async (rootDir: string): Promise<string[]> => {\n try {\n const files = await readdir(rootDir);\n\n return files.filter(\n (file) => file === 'tsconfig.json' || /^tsconfig\\..+\\.json$/.test(file)\n );\n } catch {\n return [];\n }\n};\n"],"mappings":";;;;;;;AAKA,MAAa,oBAAoB,OAAO,YAAuC;CAC7E,IAAI;EAGF,QAAO,UAFaA,0BAAQ,OAAO,EAEvB,CAAC,QACV,SAAS,SAAS,mBAAmB,uBAAuB,KAAK,IAAI,CACxE;CACF,QAAQ;EACN,OAAO,CAAC;CACV;AACF"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/init/utils/version.ts
4
3
  /**
5
4
  * Returns true when the dependency `version` range targets a major >= `major`.
@@ -1 +1 @@
1
- {"version":3,"file":"version.cjs","names":[],"sources":["../../../../src/init/utils/version.ts"],"sourcesContent":["/**\n * Returns true when the dependency `version` range targets a major >= `major`.\n * Tolerant of leading range characters, e.g. `^16.0.0`, `~16`, `16.1.0`.\n */\nexport const isVersionAtLeast = (\n version: string | undefined,\n major: number\n): boolean => {\n if (!version || typeof version !== 'string') return false;\n const match = version.match(/(\\d+)/);\n if (!match?.[1]) return false;\n return parseInt(match[1], 10) >= major;\n};\n"],"mappings":";;;;;;;AAIA,MAAa,oBACX,SACA,UACY;CACZ,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU,OAAO;CACpD,MAAM,QAAQ,QAAQ,MAAM,OAAO;CACnC,IAAI,CAAC,QAAQ,IAAI,OAAO;CACxB,OAAO,SAAS,MAAM,IAAI,EAAE,KAAK;AACnC"}
1
+ {"version":3,"file":"version.cjs","names":[],"sources":["../../../../src/init/utils/version.ts"],"sourcesContent":["/**\n * Returns true when the dependency `version` range targets a major >= `major`.\n * Tolerant of leading range characters, e.g. `^16.0.0`, `~16`, `16.1.0`.\n */\nexport const isVersionAtLeast = (\n version: string | undefined,\n major: number\n): boolean => {\n if (!version || typeof version !== 'string') return false;\n const match = version.match(/(\\d+)/);\n if (!match?.[1]) return false;\n return parseInt(match[1], 10) >= major;\n};\n"],"mappings":";;;;;;AAIA,MAAa,oBACX,SACA,UACY;CACZ,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU,OAAO;CACpD,MAAM,QAAQ,QAAQ,MAAM,OAAO;CACnC,IAAI,CAAC,QAAQ,IAAI,OAAO;CACxB,OAAO,SAAS,MAAM,IAAI,EAAE,KAAK;AACnC"}
@@ -23,18 +23,22 @@ const getTemplatePath = (format) => {
23
23
  const initConfig = async (format, baseDir, options) => {
24
24
  const { configurationFilePath } = (0, _intlayer_config_node.searchConfigurationFile)(baseDir);
25
25
  if (configurationFilePath) {
26
- (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)((0, node_path.relative)(baseDir, configurationFilePath))} already exists`);
26
+ const relativePath = (0, node_path.relative)(baseDir, configurationFilePath);
27
+ (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)(relativePath)} already exists`);
27
28
  return;
28
29
  }
29
30
  const extension = format.split(".").pop();
30
- let configContent = require__utils_asset.readAsset(getTemplatePath(extension));
31
+ const templatePath = getTemplatePath(extension);
32
+ let configContent = require__utils_asset.readAsset(templatePath);
31
33
  const { locales, applicationURL } = options ?? {};
32
- if (locales && locales.length > 0) if (extension === "json") {
33
- const localesString = JSON.stringify(locales);
34
- configContent = configContent.replace("[\"en\"]", localesString);
35
- } else {
36
- const localesString = `[${locales.map((locale) => `'${locale}'`).join(", ")}]`;
37
- configContent = configContent.replace("[Locales.ENGLISH]", localesString);
34
+ if (locales && locales.length > 0) {
35
+ if (extension === "json") {
36
+ const localesString = JSON.stringify(locales);
37
+ configContent = configContent.replace("[\"en\"]", localesString);
38
+ } else {
39
+ const localesString = `[${locales.map((locale) => `'${locale}'`).join(", ")}]`;
40
+ configContent = configContent.replace("[Locales.ENGLISH]", localesString);
41
+ }
38
42
  }
39
43
  if (applicationURL) configContent = configContent.replace("http://localhost:3000", applicationURL);
40
44
  await (0, node_fs_promises.writeFile)((0, node_path.join)(baseDir, format), configContent, "utf8");
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["v","readAsset"],"sources":["../../../src/initConfig/index.ts"],"sourcesContent":["import { writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { colorizePath, logger, v } from '@intlayer/config/logger';\nimport {\n type configurationFilesCandidates,\n searchConfigurationFile,\n} from '@intlayer/config/node';\n\ntype ConfigFormat = 'ts' | 'cjs' | 'mjs' | 'js' | 'json';\n\nconst getTemplatePath = (format: ConfigFormat) => {\n switch (format) {\n case 'ts':\n return './templates/ts.txt';\n case 'cjs':\n return './templates/cjs.txt';\n case 'mjs':\n return './templates/mjs.txt';\n case 'js':\n return './templates/mjs.txt';\n case 'json':\n return './templates/json.txt';\n default:\n return './templates/ts.txt';\n }\n};\n\n/** Values injected into the configuration file template. */\nexport type InitConfigOptions = {\n /** Locales detected in the project, inserted into `internationalization.locales`. */\n locales?: string[];\n /**\n * Dev-server URL of the detected framework, inserted as\n * `editor.applicationURL` (the template defaults to `http://localhost:3000`).\n */\n applicationURL?: string;\n};\n\n/**\n * Initialize the Intlayer configuration file. No-ops when a configuration file\n * already exists at `baseDir`.\n */\nexport const initConfig = async (\n format: (typeof configurationFilesCandidates)[number],\n baseDir: string,\n options?: InitConfigOptions\n) => {\n // Search for configuration file\n const { configurationFilePath } = searchConfigurationFile(baseDir);\n\n // return if the configuration file is found\n if (configurationFilePath) {\n const relativePath = relative(baseDir, configurationFilePath);\n logger(`${v} ${colorizePath(relativePath)} already exists`);\n return;\n }\n\n // Extract the format from the filename (e.g. 'intlayer.config.ts' -> 'ts')\n const extension = format.split('.').pop() as ConfigFormat;\n\n const templatePath = getTemplatePath(extension);\n let configContent = readAsset(templatePath);\n\n const { locales, applicationURL } = options ?? {};\n\n if (locales && locales.length > 0) {\n if (extension === 'json') {\n const localesString = JSON.stringify(locales);\n configContent = configContent.replace('[\"en\"]', localesString);\n } else {\n const localesString = `[${locales.map((locale) => `'${locale}'`).join(', ')}]`;\n configContent = configContent.replace('[Locales.ENGLISH]', localesString);\n }\n }\n\n if (applicationURL) {\n configContent = configContent.replace(\n 'http://localhost:3000',\n applicationURL\n );\n }\n\n await writeFile(join(baseDir, format), configContent, 'utf8');\n logger(`${v} Created ${colorizePath(format)}`);\n};\n"],"mappings":";;;;;;;;AAWA,MAAM,mBAAmB,WAAyB;CAChD,QAAQ,QAAR;EACE,KAAK,MACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;AAiBA,MAAa,aAAa,OACxB,QACA,SACA,YACG;CAEH,MAAM,EAAE,6EAAkD,OAAO;CAGjE,IAAI,uBAAuB;EAEzB,oCAAO,GAAGA,0BAAE,qEADkB,SAAS,qBACA,CAAC,EAAE,gBAAgB;EAC1D;CACF;CAGA,MAAM,YAAY,OAAO,MAAM,GAAG,CAAC,CAAC,IAAI;CAGxC,IAAI,gBAAgBC,+BADC,gBAAgB,SACI,CAAC;CAE1C,MAAM,EAAE,SAAS,mBAAmB,WAAW,CAAC;CAEhD,IAAI,WAAW,QAAQ,SAAS,GAC9B,IAAI,cAAc,QAAQ;EACxB,MAAM,gBAAgB,KAAK,UAAU,OAAO;EAC5C,gBAAgB,cAAc,QAAQ,YAAU,aAAa;CAC/D,OAAO;EACL,MAAM,gBAAgB,IAAI,QAAQ,KAAK,WAAW,IAAI,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;EAC5E,gBAAgB,cAAc,QAAQ,qBAAqB,aAAa;CAC1E;CAGF,IAAI,gBACF,gBAAgB,cAAc,QAC5B,yBACA,cACF;CAGF,0DAAqB,SAAS,MAAM,GAAG,eAAe,MAAM;CAC5D,oCAAO,GAAGD,0BAAE,qDAAwB,MAAM,GAAG;AAC/C"}
1
+ {"version":3,"file":"index.cjs","names":["searchConfigurationFile","relative","v","colorizePath","readAsset","writeFile","join"],"sources":["../../../src/initConfig/index.ts"],"sourcesContent":["import { writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { colorizePath, logger, v } from '@intlayer/config/logger';\nimport {\n type configurationFilesCandidates,\n searchConfigurationFile,\n} from '@intlayer/config/node';\n\ntype ConfigFormat = 'ts' | 'cjs' | 'mjs' | 'js' | 'json';\n\nconst getTemplatePath = (format: ConfigFormat) => {\n switch (format) {\n case 'ts':\n return './templates/ts.txt';\n case 'cjs':\n return './templates/cjs.txt';\n case 'mjs':\n return './templates/mjs.txt';\n case 'js':\n return './templates/mjs.txt';\n case 'json':\n return './templates/json.txt';\n default:\n return './templates/ts.txt';\n }\n};\n\n/** Values injected into the configuration file template. */\nexport type InitConfigOptions = {\n /** Locales detected in the project, inserted into `internationalization.locales`. */\n locales?: string[];\n /**\n * Dev-server URL of the detected framework, inserted as\n * `editor.applicationURL` (the template defaults to `http://localhost:3000`).\n */\n applicationURL?: string;\n};\n\n/**\n * Initialize the Intlayer configuration file. No-ops when a configuration file\n * already exists at `baseDir`.\n */\nexport const initConfig = async (\n format: (typeof configurationFilesCandidates)[number],\n baseDir: string,\n options?: InitConfigOptions\n) => {\n // Search for configuration file\n const { configurationFilePath } = searchConfigurationFile(baseDir);\n\n // return if the configuration file is found\n if (configurationFilePath) {\n const relativePath = relative(baseDir, configurationFilePath);\n logger(`${v} ${colorizePath(relativePath)} already exists`);\n return;\n }\n\n // Extract the format from the filename (e.g. 'intlayer.config.ts' -> 'ts')\n const extension = format.split('.').pop() as ConfigFormat;\n\n const templatePath = getTemplatePath(extension);\n let configContent = readAsset(templatePath);\n\n const { locales, applicationURL } = options ?? {};\n\n if (locales && locales.length > 0) {\n if (extension === 'json') {\n const localesString = JSON.stringify(locales);\n configContent = configContent.replace('[\"en\"]', localesString);\n } else {\n const localesString = `[${locales.map((locale) => `'${locale}'`).join(', ')}]`;\n configContent = configContent.replace('[Locales.ENGLISH]', localesString);\n }\n }\n\n if (applicationURL) {\n configContent = configContent.replace(\n 'http://localhost:3000',\n applicationURL\n );\n }\n\n await writeFile(join(baseDir, format), configContent, 'utf8');\n logger(`${v} Created ${colorizePath(format)}`);\n};\n"],"mappings":";;;;;;;;AAWA,MAAM,mBAAmB,WAAyB;CAChD,QAAQ,QAAR;EACE,KAAK,MACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;AAiBA,MAAa,aAAa,OACxB,QACA,SACA,YACG;CAEH,MAAM,EAAE,8BAA0BA,+CAAwB,OAAO;CAGjE,IAAI,uBAAuB;EACzB,MAAM,mBAAeC,oBAAS,SAAS,qBAAqB;EAC5D,oCAAO,GAAGC,0BAAE,OAAGC,sCAAa,YAAY,EAAE,gBAAgB;EAC1D;CACF;CAGA,MAAM,YAAY,OAAO,MAAM,GAAG,CAAC,CAAC,IAAI;CAExC,MAAM,eAAe,gBAAgB,SAAS;CAC9C,IAAI,gBAAgBC,+BAAU,YAAY;CAE1C,MAAM,EAAE,SAAS,mBAAmB,WAAW,CAAC;CAEhD,IAAI,WAAW,QAAQ,SAAS,GAAG;EACjC,IAAI,cAAc,QAAQ;GACxB,MAAM,gBAAgB,KAAK,UAAU,OAAO;GAC5C,gBAAgB,cAAc,QAAQ,YAAU,aAAa;EAC/D,OAAO;GACL,MAAM,gBAAgB,IAAI,QAAQ,KAAK,WAAW,IAAI,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;GAC5E,gBAAgB,cAAc,QAAQ,qBAAqB,aAAa;EAC1E;CACF;CAEA,IAAI,gBACF,gBAAgB,cAAc,QAC5B,yBACA,cACF;CAGF,UAAMC,gCAAUC,gBAAK,SAAS,MAAM,GAAG,eAAe,MAAM;CAC5D,oCAAO,GAAGJ,0BAAE,eAAWC,sCAAa,MAAM,GAAG;AAC/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["readAsset","path","fs","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid:\n 'Integrates Intlayer internationalization with SolidJS components. Use when the user asks to \"setup SolidJS i18n\", use the \"useIntlayer\" hook in Solid, or manage locales in a SolidJS application.',\n Astro: 'Astro-specific usage and getIntlayer',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\nexport const getInitialSkills = (\n deps: Record<string, string>\n): (keyof typeof SKILLS_METADATA)[] => {\n const skills: (keyof typeof SKILLS_METADATA)[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n ];\n\n if (deps.next) skills.push('NextJS');\n if (deps.react || !deps.next) skills.push('React');\n if (deps.preact) skills.push('Preact');\n if (deps['solid-js']) skills.push('Solid');\n if (deps.vue || deps.nuxt) skills.push('Vue');\n if (deps.svelte || deps['@sveltejs/kit']) skills.push('Svelte');\n if (deps.astro) skills.push('Astro');\n\n return skills;\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/**\n * Fetches the content of a URL using native fetch.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n const parsed = new URL(url);\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n const response = await fetch(url, { redirect: 'error' });\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n return response.text();\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform].dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs.filter((slug) => slug !== 'doc').join('_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["readAsset","path","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid:\n 'Integrates Intlayer internationalization with SolidJS components. Use when the user asks to \"setup SolidJS i18n\", use the \"useIntlayer\" hook in Solid, or manage locales in a SolidJS application.',\n Astro: 'Astro-specific usage and getIntlayer',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\nexport const getInitialSkills = (\n deps: Record<string, string>\n): (keyof typeof SKILLS_METADATA)[] => {\n const skills: (keyof typeof SKILLS_METADATA)[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n ];\n\n if (deps.next) skills.push('NextJS');\n if (deps.react || !deps.next) skills.push('React');\n if (deps.preact) skills.push('Preact');\n if (deps['solid-js']) skills.push('Solid');\n if (deps.vue || deps.nuxt) skills.push('Vue');\n if (deps.svelte || deps['@sveltejs/kit']) skills.push('Svelte');\n if (deps.astro) skills.push('Astro');\n\n return skills;\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/**\n * Fetches the content of a URL using native fetch.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n const parsed = new URL(url);\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n const response = await fetch(url, { redirect: 'error' });\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n return response.text();\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform].dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs.filter((slug) => slug !== 'doc').join('_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
@@ -16,12 +16,13 @@ const listDictionaries = async (configuration) => {
16
16
  const filePromises = fileExtensions.flatMap((ext) => contentDir.map((dir) => `${(0, _intlayer_config_utils.normalizePath)(dir)}/**/*${ext}`.replace("//", "/"))).map(async (pattern) => {
17
17
  const magicIndex = pattern.search(/[*?{}(]/);
18
18
  const basePattern = magicIndex > -1 ? pattern.slice(0, magicIndex) : pattern;
19
+ const applicableIgnore = excludedPath.filter((excludePattern) => {
20
+ const cleanName = excludePattern.replace(/\*\*/g, "").replace(/\//g, "");
21
+ if (cleanName && basePattern.includes(`/${cleanName}/`)) return false;
22
+ return true;
23
+ });
19
24
  return (0, fast_glob.default)(pattern, {
20
- ignore: excludedPath.filter((excludePattern) => {
21
- const cleanName = excludePattern.replace(/\*\*/g, "").replace(/\//g, "");
22
- if (cleanName && basePattern.includes(`/${cleanName}/`)) return false;
23
- return true;
24
- }),
25
+ ignore: applicableIgnore,
25
26
  absolute: true,
26
27
  dot: true
27
28
  });