@intlayer/engine 9.3.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 (287) hide show
  1. package/README.md +24 -24
  2. package/dist/assets/initConfig/templates/cjs.txt +1 -1
  3. package/dist/assets/initConfig/templates/mjs.txt +1 -1
  4. package/dist/assets/initConfig/templates/ts.txt +1 -1
  5. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  6. package/dist/cjs/_virtual/_utils_asset.cjs +2 -1
  7. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  8. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs +2 -1
  9. package/dist/cjs/buildIntlayerDictionary/writeDynamicDictionary.cjs.map +1 -1
  10. package/dist/cjs/buildIntlayerDictionary/writeFetchDictionary.cjs.map +1 -1
  11. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs +2 -1
  12. package/dist/cjs/buildIntlayerDictionary/writeMergedDictionary.cjs.map +1 -1
  13. package/dist/cjs/buildIntlayerDictionary/writeNestedDictionary.cjs.map +1 -1
  14. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs +4 -2
  15. package/dist/cjs/buildIntlayerDictionary/writeRemoteDictionary.cjs.map +1 -1
  16. package/dist/cjs/buildIntlayerDictionary/writeUnmergedDictionary.cjs.map +1 -1
  17. package/dist/cjs/cleanOutputDir.cjs.map +1 -1
  18. package/dist/cjs/cleanRemovedContentDeclaration.cjs +7 -4
  19. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  20. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs +5 -3
  21. package/dist/cjs/createDictionaryEntryPoint/createDictionaryEntryPoint.cjs.map +1 -1
  22. package/dist/cjs/createDictionaryEntryPoint/generateDictionaryListContent.cjs.map +1 -1
  23. package/dist/cjs/createDictionaryEntryPoint/getBuiltDictionariesPath.cjs.map +1 -1
  24. package/dist/cjs/createDictionaryEntryPoint/getBuiltDynamicDictionariesPath.cjs.map +1 -1
  25. package/dist/cjs/createDictionaryEntryPoint/getBuiltFetchDictionariesPath.cjs.map +1 -1
  26. package/dist/cjs/createDictionaryEntryPoint/getBuiltRemoteDictionariesPath.cjs.map +1 -1
  27. package/dist/cjs/createDictionaryEntryPoint/getBuiltUnmergedDictionariesPath.cjs.map +1 -1
  28. package/dist/cjs/createType/createModuleAugmentation.cjs +2 -1
  29. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  30. package/dist/cjs/createType/createType.cjs.map +1 -1
  31. package/dist/cjs/detectFormatCommand.cjs.map +1 -1
  32. package/dist/cjs/docReview/alignBlocks.cjs +1 -1
  33. package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
  34. package/dist/cjs/docReview/computeSimilarity.cjs +0 -1
  35. package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -1
  36. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +0 -1
  37. package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -1
  38. package/dist/cjs/docReview/normalizeBlock.cjs +0 -1
  39. package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -1
  40. package/dist/cjs/docReview/planActions.cjs +0 -1
  41. package/dist/cjs/docReview/planActions.cjs.map +1 -1
  42. package/dist/cjs/docReview/rebuildDocument.cjs +0 -1
  43. package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
  44. package/dist/cjs/docReview/reviewReport.cjs +2 -1
  45. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  46. package/dist/cjs/docReview/segmentDocument.cjs +0 -1
  47. package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
  48. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  49. package/dist/cjs/filterInvalidDictionaries.cjs.map +1 -1
  50. package/dist/cjs/formatDictionary.cjs.map +1 -1
  51. package/dist/cjs/getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs.map +1 -1
  52. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +4 -2
  53. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs.map +1 -1
  54. package/dist/cjs/handleContentDeclarationFileChange.cjs +6 -2
  55. package/dist/cjs/handleContentDeclarationFileChange.cjs.map +1 -1
  56. package/dist/cjs/handleContentDeclarationFileMoved.cjs.map +1 -1
  57. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +4 -2
  58. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs.map +1 -1
  59. package/dist/cjs/init/cms.cjs.map +1 -1
  60. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -1
  61. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +1 -3
  62. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  63. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +2 -1
  64. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -1
  65. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +0 -1
  66. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
  67. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -1
  68. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +3 -5
  69. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  70. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +2 -1
  71. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -1
  72. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +18 -12
  73. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
  74. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +57 -14
  75. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  76. package/dist/cjs/init/index.cjs +66 -38
  77. package/dist/cjs/init/index.cjs.map +1 -1
  78. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  79. package/dist/cjs/init/utils/fileSystem.cjs +3 -1
  80. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  81. package/dist/cjs/init/utils/githubActions.cjs.map +1 -1
  82. package/dist/cjs/init/utils/jsonParser.cjs +0 -1
  83. package/dist/cjs/init/utils/jsonParser.cjs.map +1 -1
  84. package/dist/cjs/init/utils/nextCompilerBabel.cjs.map +1 -1
  85. package/dist/cjs/init/utils/packageManager.cjs +4 -2
  86. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  87. package/dist/cjs/init/utils/tsConfig.cjs.map +1 -1
  88. package/dist/cjs/init/utils/version.cjs +0 -1
  89. package/dist/cjs/init/utils/version.cjs.map +1 -1
  90. package/dist/cjs/initConfig/index.cjs +12 -8
  91. package/dist/cjs/initConfig/index.cjs.map +1 -1
  92. package/dist/cjs/installSkills/index.cjs.map +1 -1
  93. package/dist/cjs/listDictionariesPath.cjs +6 -5
  94. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  95. package/dist/cjs/listGitFiles.cjs.map +1 -1
  96. package/dist/cjs/listProjects.cjs +2 -1
  97. package/dist/cjs/listProjects.cjs.map +1 -1
  98. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs +2 -1
  99. package/dist/cjs/loadDictionaries/getIntlayerBundle.cjs.map +1 -1
  100. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +8 -5
  101. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  102. package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
  103. package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
  104. package/dist/cjs/loadDictionaries/loadMarkdownContentDeclaration.cjs.map +1 -1
  105. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  106. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs +2 -1
  107. package/dist/cjs/loadDictionaries/loadYamlContentDeclaration.cjs.map +1 -1
  108. package/dist/cjs/loadDictionaries/log.cjs +10 -6
  109. package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
  110. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  111. package/dist/cjs/logConfigDetails.cjs +4 -3
  112. package/dist/cjs/logConfigDetails.cjs.map +1 -1
  113. package/dist/cjs/prepareIntlayer.cjs +5 -3
  114. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  115. package/dist/cjs/reduceDictionaryContent/applyMask.cjs +0 -1
  116. package/dist/cjs/reduceDictionaryContent/applyMask.cjs.map +1 -1
  117. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs +2 -1
  118. package/dist/cjs/reduceDictionaryContent/reduceDictionaryContent.cjs.map +1 -1
  119. package/dist/cjs/scan/calculateScore.cjs +0 -1
  120. package/dist/cjs/scan/calculateScore.cjs.map +1 -1
  121. package/dist/cjs/scan/checks.cjs +1 -1
  122. package/dist/cjs/scan/checks.cjs.map +1 -1
  123. package/dist/cjs/scan/parseHtml.cjs +0 -1
  124. package/dist/cjs/scan/parseHtml.cjs.map +1 -1
  125. package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
  126. package/dist/cjs/syncPluginKit/createFileAdapter.cjs +2 -1
  127. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -1
  128. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +4 -1
  129. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -1
  130. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +0 -1
  131. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -1
  132. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +0 -1
  133. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -1
  134. package/dist/cjs/utils/autoDecorateContent.cjs.map +1 -1
  135. package/dist/cjs/utils/babelParser.cjs.map +1 -1
  136. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  137. package/dist/cjs/utils/buildFilesList.cjs.map +1 -1
  138. package/dist/cjs/utils/chunkArray.cjs +0 -1
  139. package/dist/cjs/utils/chunkArray.cjs.map +1 -1
  140. package/dist/cjs/utils/formatter.cjs.map +1 -1
  141. package/dist/cjs/utils/getContentExtension.cjs +1 -4
  142. package/dist/cjs/utils/getContentExtension.cjs.map +1 -1
  143. package/dist/cjs/utils/getFormatFromExtension.cjs +0 -1
  144. package/dist/cjs/utils/getFormatFromExtension.cjs.map +1 -1
  145. package/dist/cjs/utils/getPathHash.cjs +0 -1
  146. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  147. package/dist/cjs/utils/mergeChunks.cjs +0 -1
  148. package/dist/cjs/utils/mergeChunks.cjs.map +1 -1
  149. package/dist/cjs/utils/pLimit.cjs +0 -1
  150. package/dist/cjs/utils/pLimit.cjs.map +1 -1
  151. package/dist/cjs/utils/readDictionariesFromDisk.cjs.map +1 -1
  152. package/dist/cjs/utils/reduceObjectFormat.cjs +0 -1
  153. package/dist/cjs/utils/reduceObjectFormat.cjs.map +1 -1
  154. package/dist/cjs/utils/resolveObjectPromises.cjs +0 -1
  155. package/dist/cjs/utils/resolveObjectPromises.cjs.map +1 -1
  156. package/dist/cjs/utils/resolveRelativePath.cjs +4 -1
  157. package/dist/cjs/utils/resolveRelativePath.cjs.map +1 -1
  158. package/dist/cjs/utils/runOnce.cjs +2 -2
  159. package/dist/cjs/utils/runOnce.cjs.map +1 -1
  160. package/dist/cjs/utils/runParallel/bin.cjs.map +1 -1
  161. package/dist/cjs/utils/runParallel/bootstrap.cjs +0 -1
  162. package/dist/cjs/utils/runParallel/bootstrap.cjs.map +1 -1
  163. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  164. package/dist/cjs/utils/runParallel/spawnPosix.cjs.map +1 -1
  165. package/dist/cjs/utils/runParallel/spawnWin32.cjs.map +1 -1
  166. package/dist/cjs/utils/sortAlphabetically.cjs +0 -1
  167. package/dist/cjs/utils/sortAlphabetically.cjs.map +1 -1
  168. package/dist/cjs/utils/splitTextByLine.cjs +0 -1
  169. package/dist/cjs/utils/splitTextByLine.cjs.map +1 -1
  170. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs +0 -1
  171. package/dist/cjs/utils/verifyIdenticObjectFormat.cjs.map +1 -1
  172. package/dist/cjs/watcher.cjs +4 -2
  173. package/dist/cjs/watcher.cjs.map +1 -1
  174. package/dist/cjs/writeConfiguration/index.cjs +2 -1
  175. package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
  176. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +0 -1
  177. package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
  178. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
  179. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +26 -23
  180. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
  181. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs +6 -5
  182. package/dist/cjs/writeContentDeclaration/transformJSONFile.cjs.map +1 -1
  183. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +9 -3
  184. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  185. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs +2 -1
  186. package/dist/cjs/writeContentDeclaration/writeJSFile.cjs.map +1 -1
  187. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -1
  188. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  189. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +4 -2
  190. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  191. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  192. package/dist/esm/_virtual/_utils_asset.mjs +2 -1
  193. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs +2 -1
  194. package/dist/esm/buildIntlayerDictionary/writeDynamicDictionary.mjs.map +1 -1
  195. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs +2 -1
  196. package/dist/esm/buildIntlayerDictionary/writeMergedDictionary.mjs.map +1 -1
  197. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs +4 -2
  198. package/dist/esm/buildIntlayerDictionary/writeRemoteDictionary.mjs.map +1 -1
  199. package/dist/esm/cleanRemovedContentDeclaration.mjs +7 -4
  200. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  201. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs +5 -3
  202. package/dist/esm/createDictionaryEntryPoint/createDictionaryEntryPoint.mjs.map +1 -1
  203. package/dist/esm/createType/createModuleAugmentation.mjs +2 -1
  204. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  205. package/dist/esm/docReview/alignBlocks.mjs +1 -1
  206. package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
  207. package/dist/esm/docReview/reviewReport.mjs +2 -1
  208. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  209. package/dist/esm/handleAdditionalContentDeclarationFile.mjs +4 -2
  210. package/dist/esm/handleAdditionalContentDeclarationFile.mjs.map +1 -1
  211. package/dist/esm/handleContentDeclarationFileChange.mjs +6 -2
  212. package/dist/esm/handleContentDeclarationFileChange.mjs.map +1 -1
  213. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +4 -2
  214. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs.map +1 -1
  215. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +1 -3
  216. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  217. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +2 -1
  218. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -1
  219. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +4 -6
  220. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  221. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +2 -1
  222. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -1
  223. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +17 -10
  224. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
  225. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +58 -15
  226. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  227. package/dist/esm/init/index.mjs +66 -38
  228. package/dist/esm/init/index.mjs.map +1 -1
  229. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  230. package/dist/esm/init/utils/fileSystem.mjs +3 -1
  231. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  232. package/dist/esm/init/utils/packageManager.mjs +4 -2
  233. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  234. package/dist/esm/initConfig/index.mjs +12 -8
  235. package/dist/esm/initConfig/index.mjs.map +1 -1
  236. package/dist/esm/listDictionariesPath.mjs +6 -5
  237. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  238. package/dist/esm/listProjects.mjs +2 -1
  239. package/dist/esm/listProjects.mjs.map +1 -1
  240. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs +2 -1
  241. package/dist/esm/loadDictionaries/getIntlayerBundle.mjs.map +1 -1
  242. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +8 -5
  243. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  244. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs +2 -1
  245. package/dist/esm/loadDictionaries/loadYamlContentDeclaration.mjs.map +1 -1
  246. package/dist/esm/loadDictionaries/log.mjs +10 -6
  247. package/dist/esm/loadDictionaries/log.mjs.map +1 -1
  248. package/dist/esm/logConfigDetails.mjs +4 -3
  249. package/dist/esm/logConfigDetails.mjs.map +1 -1
  250. package/dist/esm/prepareIntlayer.mjs +5 -3
  251. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  252. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs +2 -1
  253. package/dist/esm/reduceDictionaryContent/reduceDictionaryContent.mjs.map +1 -1
  254. package/dist/esm/scan/checks.mjs +1 -1
  255. package/dist/esm/scan/checks.mjs.map +1 -1
  256. package/dist/esm/syncPluginKit/createFileAdapter.mjs +2 -1
  257. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -1
  258. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +4 -1
  259. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -1
  260. package/dist/esm/utils/babelParser.mjs.map +1 -1
  261. package/dist/esm/utils/getContentExtension.mjs +1 -3
  262. package/dist/esm/utils/getContentExtension.mjs.map +1 -1
  263. package/dist/esm/utils/resolveRelativePath.mjs +4 -1
  264. package/dist/esm/utils/resolveRelativePath.mjs.map +1 -1
  265. package/dist/esm/utils/runOnce.mjs +2 -2
  266. package/dist/esm/utils/runOnce.mjs.map +1 -1
  267. package/dist/esm/watcher.mjs +4 -2
  268. package/dist/esm/watcher.mjs.map +1 -1
  269. package/dist/esm/writeConfiguration/index.mjs +2 -1
  270. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  271. package/dist/esm/writeContentDeclaration/transformJSFile.mjs +26 -23
  272. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  273. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs +6 -5
  274. package/dist/esm/writeContentDeclaration/transformJSONFile.mjs.map +1 -1
  275. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +9 -3
  276. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  277. package/dist/esm/writeContentDeclaration/writeJSFile.mjs +2 -1
  278. package/dist/esm/writeContentDeclaration/writeJSFile.mjs.map +1 -1
  279. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -1
  280. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  281. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +4 -2
  282. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  283. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +9 -4
  284. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  285. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +6 -2
  286. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  287. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"restructure.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/restructure.ts"],"sourcesContent":["import { mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport fg from 'fast-glob';\nimport type { RoutingMode } from '../../utils/configManipulation';\nimport { rewriteRelativeImports } from '../nextAppRouter/restructure';\n\n/** Source file extensions whose relative imports must be rewritten after a move. */\nconst SCRIPT_GLOB = '**/*.{ts,tsx,js,jsx,mjs,cjs}';\n\n/**\n * The optional TanStack Router locale segment directory (`{-$locale}` param),\n * used by every routing mode except `prefix-all` so the default locale stays\n * prefix-free.\n */\nexport const LOCALE_SEGMENT = '{-$locale}';\n\n/**\n * The required TanStack Router locale segment directory (`$locale` param), used\n * by `prefix-all` routing where every URL — including the default locale — is\n * prefixed.\n */\nexport const PREFIX_ALL_LOCALE_SEGMENT = '$locale';\n\n/**\n * Picks the locale segment directory for the project's routing mode. `prefix-all`\n * requires the mandatory `$locale` param so the default locale is also prefixed;\n * all other modes use the optional `{-$locale}` param so the default locale stays\n * prefix-free.\n */\nexport const getLocaleSegment = (routingMode: RoutingMode): string =>\n routingMode === 'prefix-all' ? PREFIX_ALL_LOCALE_SEGMENT : LOCALE_SEGMENT;\n\n/**\n * Detects whether a top-level route entry is already a locale segment, in any of\n * the TanStack Router param forms:\n * - `{-$locale}` — optional param (prefix every locale except the default),\n * - `$locale` / `{$locale}` — required param (prefix **all** locales).\n *\n * Used to skip the restructure when the project is already locale-aware, so an\n * existing prefix-all `$locale` directory is never nested under a freshly created\n * `{-$locale}` (which would produce `{-$locale}/$locale`).\n */\nexport const isLocaleSegment = (entryName: string): boolean =>\n /^(\\{-?\\$locale\\}|\\$locale)$/.test(entryName);\n\n/** Strips a known script extension from a file name, e.g. `index.tsx` -> `index`. */\nconst stripScriptExtension = (fileName: string): string =>\n fileName.replace(/\\.(tsx|ts|jsx|js|mjs|cjs)$/, '');\n\n/**\n * Routes-directory entries that must stay at the root and never be moved under\n * `{-$locale}`:\n * - `__root` (the root route document),\n * - `routeTree.gen` (generated route tree),\n * - `api` (server / API routes — these are not locale-prefixed),\n * - TanStack-ignored entries prefixed with `-` (e.g. `-components`, `-utils`),\n * - stylesheets.\n *\n * Everything else (route files and nested route folders) is moved so it becomes\n * locale-aware.\n */\nexport const shouldKeepRouteAtRoot = (entryName: string): boolean => {\n if (entryName.startsWith('-')) return true;\n if (entryName.toLowerCase().endsWith('.css')) return true;\n\n const base = stripScriptExtension(entryName);\n const keepExactBases = new Set(['__root', 'routeTree.gen', 'api']);\n return keepExactBases.has(base);\n};\n\n/** Outcome of an attempted `{-$locale}` restructure. */\nexport type RestructureResult =\n | { status: 'already-structured'; localeSegment: string }\n | { status: 'nothing-to-move' }\n | { status: 'moved'; movedEntries: string[] };\n\n/**\n * Moves the routable entries of `routesDir` under a new `localeSegment` directory\n * (the optional `{-$locale}` by default, or the required `$locale` for\n * `prefix-all`) and rewrites relative imports in the moved files. Idempotent: a\n * no-op when the routes are already locale-aware in any prefix mode (see\n * {@link isLocaleSegment}), which is reported via `localeSegment`. Root-only\n * files (see {@link shouldKeepRouteAtRoot}) are left in place.\n */\nexport const restructureRoutesIntoLocale = async (\n rootDir: string,\n routesDir: string,\n localeSegment: string = LOCALE_SEGMENT\n): Promise<RestructureResult> => {\n const routesDirAbs = join(rootDir, routesDir);\n const localeDirAbs = join(routesDirAbs, localeSegment);\n\n const entries = await readdir(routesDirAbs, { withFileTypes: true });\n\n // Skip when the routes are already locale-aware in any prefix mode — a fresh\n // `{-$locale}`, or an existing `$locale` / `{$locale}` (prefix-all) segment.\n const existingLocaleSegment = entries.find((entry) =>\n isLocaleSegment(entry.name)\n );\n if (existingLocaleSegment) {\n return {\n status: 'already-structured',\n localeSegment: existingLocaleSegment.name,\n };\n }\n\n const movedTopLevelNames = entries\n .map((entry) => entry.name)\n .filter((name) => !shouldKeepRouteAtRoot(name));\n\n if (movedTopLevelNames.length === 0) {\n return { status: 'nothing-to-move' };\n }\n\n await mkdir(localeDirAbs, { recursive: true });\n\n for (const name of movedTopLevelNames) {\n await rename(join(routesDirAbs, name), join(localeDirAbs, name));\n }\n\n const movedFiles = await fg(SCRIPT_GLOB, {\n cwd: localeDirAbs,\n absolute: true,\n onlyFiles: true,\n });\n\n const rewriteContext = {\n appDirAbs: routesDirAbs,\n localeDirAbs,\n movedTopLevelNames,\n };\n\n for (const newAbs of movedFiles) {\n const relFromLocale = relative(localeDirAbs, newAbs);\n const oldAbs = join(routesDirAbs, relFromLocale);\n const code = await readFile(newAbs, 'utf8');\n const rewritten = rewriteRelativeImports(\n code,\n oldAbs,\n newAbs,\n rewriteContext\n );\n if (rewritten !== code) {\n await writeFile(newAbs, rewritten, 'utf8');\n }\n }\n\n return { status: 'moved', movedEntries: movedTopLevelNames };\n};\n"],"mappings":";;;;;;;AAOA,MAAM,cAAc;;;;;;AAOpB,MAAa,iBAAiB;;;;;;AAO9B,MAAa,4BAA4B;;;;;;;AAQzC,MAAa,oBAAoB,gBAC/B,gBAAgB,eAAe,4BAA4B;;;;;;;;;;;AAY7D,MAAa,mBAAmB,cAC9B,8BAA8B,KAAK,SAAS;;AAG9C,MAAM,wBAAwB,aAC5B,SAAS,QAAQ,8BAA8B,EAAE;;;;;;;;;;;;;AAcnD,MAAa,yBAAyB,cAA+B;CACnE,IAAI,UAAU,WAAW,GAAG,GAAG,OAAO;CACtC,IAAI,UAAU,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,OAAO;CAErD,MAAM,OAAO,qBAAqB,SAAS;CAE3C,wBAAO,IADoB,IAAI;EAAC;EAAU;EAAiB;CAAK,CAC5C,EAAC,CAAC,IAAI,IAAI;AAChC;;;;;;;;;AAgBA,MAAa,8BAA8B,OACzC,SACA,WACA,gBAAwB,mBACO;CAC/B,MAAM,eAAe,KAAK,SAAS,SAAS;CAC5C,MAAM,eAAe,KAAK,cAAc,aAAa;CAErD,MAAM,UAAU,MAAM,QAAQ,cAAc,EAAE,eAAe,KAAK,CAAC;CAInE,MAAM,wBAAwB,QAAQ,MAAM,UAC1C,gBAAgB,MAAM,IAAI,CAC5B;CACA,IAAI,uBACF,OAAO;EACL,QAAQ;EACR,eAAe,sBAAsB;CACvC;CAGF,MAAM,qBAAqB,QACxB,KAAK,UAAU,MAAM,IAAI,CAAC,CAC1B,QAAQ,SAAS,CAAC,sBAAsB,IAAI,CAAC;CAEhD,IAAI,mBAAmB,WAAW,GAChC,OAAO,EAAE,QAAQ,kBAAkB;CAGrC,MAAM,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;CAE7C,KAAK,MAAM,QAAQ,oBACjB,MAAM,OAAO,KAAK,cAAc,IAAI,GAAG,KAAK,cAAc,IAAI,CAAC;CAGjE,MAAM,aAAa,MAAM,GAAG,aAAa;EACvC,KAAK;EACL,UAAU;EACV,WAAW;CACb,CAAC;CAED,MAAM,iBAAiB;EACrB,WAAW;EACX;EACA;CACF;CAEA,KAAK,MAAM,UAAU,YAAY;EAE/B,MAAM,SAAS,KAAK,cADE,SAAS,cAAc,MACC,CAAC;EAC/C,MAAM,OAAO,MAAM,SAAS,QAAQ,MAAM;EAC1C,MAAM,YAAY,uBAChB,MACA,QACA,QACA,cACF;EACA,IAAI,cAAc,MAChB,MAAM,UAAU,QAAQ,WAAW,MAAM;CAE7C;CAEA,OAAO;EAAE,QAAQ;EAAS,cAAc;CAAmB;AAC7D"}
1
+ {"version":3,"file":"restructure.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/restructure.ts"],"sourcesContent":["import { mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport fg from 'fast-glob';\nimport type { RoutingMode } from '../../utils/configManipulation';\nimport { rewriteRelativeImports } from '../nextAppRouter/restructure';\n\n/** Source file extensions whose relative imports must be rewritten after a move. */\nconst SCRIPT_GLOB = '**/*.{ts,tsx,js,jsx,mjs,cjs}';\n\n/**\n * The optional TanStack Router locale segment directory (`{-$locale}` param),\n * used by every routing mode except `prefix-all` so the default locale stays\n * prefix-free.\n */\nexport const LOCALE_SEGMENT = '{-$locale}';\n\n/**\n * The required TanStack Router locale segment directory (`$locale` param), used\n * by `prefix-all` routing where every URL — including the default locale — is\n * prefixed.\n */\nexport const PREFIX_ALL_LOCALE_SEGMENT = '$locale';\n\n/**\n * Picks the locale segment directory for the project's routing mode. `prefix-all`\n * requires the mandatory `$locale` param so the default locale is also prefixed;\n * all other modes use the optional `{-$locale}` param so the default locale stays\n * prefix-free.\n */\nexport const getLocaleSegment = (routingMode: RoutingMode): string =>\n routingMode === 'prefix-all' ? PREFIX_ALL_LOCALE_SEGMENT : LOCALE_SEGMENT;\n\n/**\n * Detects whether a top-level route entry is already a locale segment, in any of\n * the TanStack Router param forms:\n * - `{-$locale}` — optional param (prefix every locale except the default),\n * - `$locale` / `{$locale}` — required param (prefix **all** locales).\n *\n * Used to skip the restructure when the project is already locale-aware, so an\n * existing prefix-all `$locale` directory is never nested under a freshly created\n * `{-$locale}` (which would produce `{-$locale}/$locale`).\n */\nexport const isLocaleSegment = (entryName: string): boolean =>\n /^(\\{-?\\$locale\\}|\\$locale)$/.test(entryName);\n\n/** Strips a known script extension from a file name, e.g. `index.tsx` -> `index`. */\nconst stripScriptExtension = (fileName: string): string =>\n fileName.replace(/\\.(tsx|ts|jsx|js|mjs|cjs)$/, '');\n\n/**\n * Routes-directory entries that must stay at the root and never be moved under\n * `{-$locale}`:\n * - `__root` (the root route document),\n * - `routeTree.gen` (generated route tree),\n * - `api` (server / API routes — these are not locale-prefixed),\n * - TanStack-ignored entries prefixed with `-` (e.g. `-components`, `-utils`),\n * - stylesheets.\n *\n * Everything else (route files and nested route folders) is moved so it becomes\n * locale-aware.\n */\nexport const shouldKeepRouteAtRoot = (entryName: string): boolean => {\n if (entryName.startsWith('-')) return true;\n if (entryName.toLowerCase().endsWith('.css')) return true;\n\n const base = stripScriptExtension(entryName);\n const keepExactBases = new Set(['__root', 'routeTree.gen', 'api']);\n return keepExactBases.has(base);\n};\n\n/** Outcome of an attempted `{-$locale}` restructure. */\nexport type RestructureResult =\n | { status: 'already-structured'; localeSegment: string }\n | { status: 'nothing-to-move' }\n | { status: 'moved'; movedEntries: string[] };\n\n/**\n * Moves the routable entries of `routesDir` under a new `localeSegment` directory\n * (the optional `{-$locale}` by default, or the required `$locale` for\n * `prefix-all`) and rewrites relative imports in the moved files. Idempotent: a\n * no-op when the routes are already locale-aware in any prefix mode (see\n * {@link isLocaleSegment}), which is reported via `localeSegment`. Root-only\n * files (see {@link shouldKeepRouteAtRoot}) are left in place.\n */\nexport const restructureRoutesIntoLocale = async (\n rootDir: string,\n routesDir: string,\n localeSegment: string = LOCALE_SEGMENT\n): Promise<RestructureResult> => {\n const routesDirAbs = join(rootDir, routesDir);\n const localeDirAbs = join(routesDirAbs, localeSegment);\n\n const entries = await readdir(routesDirAbs, { withFileTypes: true });\n\n // Skip when the routes are already locale-aware in any prefix mode — a fresh\n // `{-$locale}`, or an existing `$locale` / `{$locale}` (prefix-all) segment.\n const existingLocaleSegment = entries.find((entry) =>\n isLocaleSegment(entry.name)\n );\n if (existingLocaleSegment) {\n return {\n status: 'already-structured',\n localeSegment: existingLocaleSegment.name,\n };\n }\n\n const movedTopLevelNames = entries\n .map((entry) => entry.name)\n .filter((name) => !shouldKeepRouteAtRoot(name));\n\n if (movedTopLevelNames.length === 0) {\n return { status: 'nothing-to-move' };\n }\n\n await mkdir(localeDirAbs, { recursive: true });\n\n for (const name of movedTopLevelNames) {\n await rename(join(routesDirAbs, name), join(localeDirAbs, name));\n }\n\n const movedFiles = await fg(SCRIPT_GLOB, {\n cwd: localeDirAbs,\n absolute: true,\n onlyFiles: true,\n });\n\n const rewriteContext = {\n appDirAbs: routesDirAbs,\n localeDirAbs,\n movedTopLevelNames,\n };\n\n for (const newAbs of movedFiles) {\n const relFromLocale = relative(localeDirAbs, newAbs);\n const oldAbs = join(routesDirAbs, relFromLocale);\n const code = await readFile(newAbs, 'utf8');\n const rewritten = rewriteRelativeImports(\n code,\n oldAbs,\n newAbs,\n rewriteContext\n );\n if (rewritten !== code) {\n await writeFile(newAbs, rewritten, 'utf8');\n }\n }\n\n return { status: 'moved', movedEntries: movedTopLevelNames };\n};\n"],"mappings":";;;;;;;AAOA,MAAM,cAAc;;;;;;AAOpB,MAAa,iBAAiB;;;;;;AAO9B,MAAa,4BAA4B;;;;;;;AAQzC,MAAa,oBAAoB,gBAC/B,gBAAgB,eAAe,4BAA4B;;;;;;;;;;;AAY7D,MAAa,mBAAmB,cAC9B,8BAA8B,KAAK,SAAS;;AAG9C,MAAM,wBAAwB,aAC5B,SAAS,QAAQ,8BAA8B,EAAE;;;;;;;;;;;;;AAcnD,MAAa,yBAAyB,cAA+B;CACnE,IAAI,UAAU,WAAW,GAAG,GAAG,OAAO;CACtC,IAAI,UAAU,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,OAAO;CAErD,MAAM,OAAO,qBAAqB,SAAS;CAE3C,wBAAO,IADoB,IAAI;EAAC;EAAU;EAAiB;CAAK,CAC5C,EAAC,CAAC,IAAI,IAAI;AAChC;;;;;;;;;AAgBA,MAAa,8BAA8B,OACzC,SACA,WACA,gBAAwB,mBACO;CAC/B,MAAM,eAAe,KAAK,SAAS,SAAS;CAC5C,MAAM,eAAe,KAAK,cAAc,aAAa;CAErD,MAAM,UAAU,MAAM,QAAQ,cAAc,EAAE,eAAe,KAAK,CAAC;CAInE,MAAM,wBAAwB,QAAQ,MAAM,UAC1C,gBAAgB,MAAM,IAAI,CAC5B;CACA,IAAI,uBACF,OAAO;EACL,QAAQ;EACR,eAAe,sBAAsB;CACvC;CAGF,MAAM,qBAAqB,QACxB,KAAK,UAAU,MAAM,IAAI,CAAC,CAC1B,QAAQ,SAAS,CAAC,sBAAsB,IAAI,CAAC;CAEhD,IAAI,mBAAmB,WAAW,GAChC,OAAO,EAAE,QAAQ,kBAAkB;CAGrC,MAAM,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;CAE7C,KAAK,MAAM,QAAQ,oBACjB,MAAM,OAAO,KAAK,cAAc,IAAI,GAAG,KAAK,cAAc,IAAI,CAAC;CAGjE,MAAM,aAAa,MAAM,GAAG,aAAa;EACvC,KAAK;EACL,UAAU;EACV,WAAW;CACb,CAAC;CAED,MAAM,iBAAiB;EACrB,WAAW;EACX;EACA;CACF;CAEA,KAAK,MAAM,UAAU,YAAY;EAC/B,MAAM,gBAAgB,SAAS,cAAc,MAAM;EACnD,MAAM,SAAS,KAAK,cAAc,aAAa;EAC/C,MAAM,OAAO,MAAM,SAAS,QAAQ,MAAM;EAC1C,MAAM,YAAY,uBAChB,MACA,QACA,QACA,cACF;EACA,IAAI,cAAc,MAChB,MAAM,UAAU,QAAQ,WAAW,MAAM;CAE7C;CAEA,OAAO;EAAE,QAAQ;EAAS,cAAc;CAAmB;AAC7D"}
@@ -33,25 +33,30 @@ export const Route = createFileRoute("/${localeSegment}")({
33
33
  `;
34
34
  /**
35
35
  * Root route document (`routes/__root.tsx`) providing `<html>` + the Intlayer
36
- * provider, with the locale read from the `{-$locale}` route param.
36
+ * provider, with the locale read from the locale segment route params.
37
+ *
38
+ * The route is reached through `getRouteApi(<route id>)` rather than by
39
+ * importing `<segment>/route`, so the root never imports a child route module —
40
+ * the recommended way to consume another route's typed hooks.
37
41
  */
38
- const ROOT_TEMPLATE_TS = `import {
42
+ const buildRootTemplateTs = (localeSegment) => `import {
39
43
  createRootRoute,
44
+ getRouteApi,
40
45
  HeadContent,
41
46
  Scripts,
42
- useParams,
43
47
  } from "@tanstack/react-router";
44
48
  import { defaultLocale, getHTMLTextDir } from "intlayer";
45
49
  import type { ReactNode } from "react";
46
50
  import { IntlayerProvider } from "react-intlayer";
47
51
 
52
+ const localeRoute = getRouteApi("/${localeSegment}");
53
+
48
54
  export const Route = createRootRoute({
49
55
  shellComponent: RootDocument,
50
56
  });
51
57
 
52
58
  function RootDocument({ children }: { children: ReactNode }) {
53
- const params = useParams({ strict: false });
54
- const locale = params.locale ?? defaultLocale;
59
+ const { locale = defaultLocale } = localeRoute.useParams();
55
60
 
56
61
  return (
57
62
  <html dir={getHTMLTextDir(locale)} lang={locale}>
@@ -66,22 +71,24 @@ function RootDocument({ children }: { children: ReactNode }) {
66
71
  );
67
72
  }
68
73
  `;
69
- const ROOT_TEMPLATE_JS = `import {
74
+ /** JavaScript counterpart of {@link buildRootTemplateTs}. */
75
+ const buildRootTemplateJs = (localeSegment) => `import {
70
76
  createRootRoute,
77
+ getRouteApi,
71
78
  HeadContent,
72
79
  Scripts,
73
- useParams,
74
80
  } from "@tanstack/react-router";
75
81
  import { defaultLocale, getHTMLTextDir } from "intlayer";
76
82
  import { IntlayerProvider } from "react-intlayer";
77
83
 
84
+ const localeRoute = getRouteApi("/${localeSegment}");
85
+
78
86
  export const Route = createRootRoute({
79
87
  shellComponent: RootDocument,
80
88
  });
81
89
 
82
90
  function RootDocument({ children }) {
83
- const params = useParams({ strict: false });
84
- const locale = params.locale ?? defaultLocale;
91
+ const { locale = defaultLocale } = localeRoute.useParams();
85
92
 
86
93
  return (
87
94
  <html dir={getHTMLTextDir(locale)} lang={locale}>
@@ -98,5 +105,5 @@ function RootDocument({ children }) {
98
105
  `;
99
106
 
100
107
  //#endregion
101
- export { ROOT_TEMPLATE_JS, ROOT_TEMPLATE_TS, buildLocaleRouteTemplate };
108
+ export { buildLocaleRouteTemplate, buildRootTemplateJs, buildRootTemplateTs };
102
109
  //# sourceMappingURL=templates.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"templates.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/templates.ts"],"sourcesContent":["/**\n * File templates for a fresh TanStack Start integration. These are only written\n * when the target file does not exist — they never overwrite user code.\n */\n\n/**\n * Builds the locale segment route (`routes/<localeSegment>/route.tsx`) for the\n * given segment. The optional `{-$locale}` param makes the default locale\n * prefix-free, while the required `$locale` param (`prefix-all`) prefixes every\n * locale; in both cases `validatePrefix` redirects unknown prefixes to a valid\n * one. Identical for TypeScript and JavaScript projects.\n */\nexport const buildLocaleRouteTemplate = (\n localeSegment: string\n): string => `import { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\";\nimport { validatePrefix } from \"intlayer\";\n\nexport const Route = createFileRoute(\"/${localeSegment}\")({\n beforeLoad: ({ params }) => {\n // beforeLoad runs on both client and server, so resolve the locale from the\n // route params rather than from request headers.\n const { isValid, localePrefix } = validatePrefix(params.locale);\n\n // A valid (or absent, i.e. default) locale prefix is fine as-is.\n if (isValid) return;\n\n // Otherwise redirect to the same route with a valid locale prefix.\n throw redirect({\n params: { locale: localePrefix },\n to: \"/${localeSegment}\",\n });\n },\n component: Outlet,\n});\n`;\n\n/**\n * Root route document (`routes/__root.tsx`) providing `<html>` + the Intlayer\n * provider, with the locale read from the `{-$locale}` route param.\n */\nexport const ROOT_TEMPLATE_TS = `import {\n createRootRoute,\n HeadContent,\n Scripts,\n useParams,\n} from \"@tanstack/react-router\";\nimport { defaultLocale, getHTMLTextDir } from \"intlayer\";\nimport type { ReactNode } from \"react\";\nimport { IntlayerProvider } from \"react-intlayer\";\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }: { children: ReactNode }) {\n const params = useParams({ strict: false });\n const locale = params.locale ?? defaultLocale;\n\n return (\n <html dir={getHTMLTextDir(locale)} lang={locale}>\n <head>\n <HeadContent />\n </head>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n\nexport const ROOT_TEMPLATE_JS = `import {\n createRootRoute,\n HeadContent,\n Scripts,\n useParams,\n} from \"@tanstack/react-router\";\nimport { defaultLocale, getHTMLTextDir } from \"intlayer\";\nimport { IntlayerProvider } from \"react-intlayer\";\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }) {\n const params = useParams({ strict: false });\n const locale = params.locale ?? defaultLocale;\n\n return (\n <html dir={getHTMLTextDir(locale)} lang={locale}>\n <head>\n <HeadContent />\n </head>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,4BACX,kBACW;;;yCAG4B,cAAc;;;;;;;;;;;;cAYzC,cAAc;;;;;;;;;;AAW5B,MAAa,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgChC,MAAa,mBAAmB"}
1
+ {"version":3,"file":"templates.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/templates.ts"],"sourcesContent":["/**\n * File templates for a fresh TanStack Start integration. These are only written\n * when the target file does not exist — they never overwrite user code.\n */\n\n/**\n * Builds the locale segment route (`routes/<localeSegment>/route.tsx`) for the\n * given segment. The optional `{-$locale}` param makes the default locale\n * prefix-free, while the required `$locale` param (`prefix-all`) prefixes every\n * locale; in both cases `validatePrefix` redirects unknown prefixes to a valid\n * one. Identical for TypeScript and JavaScript projects.\n */\nexport const buildLocaleRouteTemplate = (\n localeSegment: string\n): string => `import { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\";\nimport { validatePrefix } from \"intlayer\";\n\nexport const Route = createFileRoute(\"/${localeSegment}\")({\n beforeLoad: ({ params }) => {\n // beforeLoad runs on both client and server, so resolve the locale from the\n // route params rather than from request headers.\n const { isValid, localePrefix } = validatePrefix(params.locale);\n\n // A valid (or absent, i.e. default) locale prefix is fine as-is.\n if (isValid) return;\n\n // Otherwise redirect to the same route with a valid locale prefix.\n throw redirect({\n params: { locale: localePrefix },\n to: \"/${localeSegment}\",\n });\n },\n component: Outlet,\n});\n`;\n\n/**\n * Root route document (`routes/__root.tsx`) providing `<html>` + the Intlayer\n * provider, with the locale read from the locale segment route params.\n *\n * The route is reached through `getRouteApi(<route id>)` rather than by\n * importing `<segment>/route`, so the root never imports a child route module —\n * the recommended way to consume another route's typed hooks.\n */\nexport const buildRootTemplateTs = (localeSegment: string): string => `import {\n createRootRoute,\n getRouteApi,\n HeadContent,\n Scripts,\n} from \"@tanstack/react-router\";\nimport { defaultLocale, getHTMLTextDir } from \"intlayer\";\nimport type { ReactNode } from \"react\";\nimport { IntlayerProvider } from \"react-intlayer\";\n\nconst localeRoute = getRouteApi(\"/${localeSegment}\");\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }: { children: ReactNode }) {\n const { locale = defaultLocale } = localeRoute.useParams();\n\n return (\n <html dir={getHTMLTextDir(locale)} lang={locale}>\n <head>\n <HeadContent />\n </head>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n\n/** JavaScript counterpart of {@link buildRootTemplateTs}. */\nexport const buildRootTemplateJs = (localeSegment: string): string => `import {\n createRootRoute,\n getRouteApi,\n HeadContent,\n Scripts,\n} from \"@tanstack/react-router\";\nimport { defaultLocale, getHTMLTextDir } from \"intlayer\";\nimport { IntlayerProvider } from \"react-intlayer\";\n\nconst localeRoute = getRouteApi(\"/${localeSegment}\");\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }) {\n const { locale = defaultLocale } = localeRoute.useParams();\n\n return (\n <html dir={getHTMLTextDir(locale)} lang={locale}>\n <head>\n <HeadContent />\n </head>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,4BACX,kBACW;;;yCAG4B,cAAc;;;;;;;;;;;;cAYzC,cAAc;;;;;;;;;;;;;;AAe5B,MAAa,uBAAuB,kBAAkC;;;;;;;;;;oCAUlC,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAwBlD,MAAa,uBAAuB,kBAAkC;;;;;;;;;oCASlC,cAAc"}
@@ -1,9 +1,11 @@
1
1
  import { babelTsParser } from "../../../utils/babelParser.mjs";
2
- import { ensureNamedImport } from "../../utils/astImports.mjs";
2
+ import { ensureNamedImport, firstInsertIndex, isModuleScopeBinding } from "../../utils/astImports.mjs";
3
3
  import * as recast from "recast";
4
4
 
5
5
  //#region src/init/frameworkSetup/tanstackStart/transforms.ts
6
6
  const { builders: b, namedTypes: n } = recast.types;
7
+ /** Module-scope identifier bound to the locale route's typed API. */
8
+ const LOCALE_ROUTE_API_VARIABLE = "localeRoute";
7
9
  /** babel-ts parser handles TypeScript *and* JSX. */
8
10
  const parseTsx = (code) => recast.parse(code, { parser: babelTsParser });
9
11
  /**
@@ -48,27 +50,59 @@ const patternBindsName = (node, name) => {
48
50
  }
49
51
  };
50
52
  /**
51
- * Inserts `const locale = …` once, at the top of the function body. A single
52
- * self-contained statement is used (rather than an intermediate `params` const)
53
- * so it can never collide with a `params` variable the document already
54
- * declares. Expression-bodied arrow functions are first converted to a block so
55
- * the declaration has somewhere to live.
53
+ * Inserts `const { locale = defaultLocale } = localeRoute.useParams();` once, at
54
+ * the top of the function body. The destructuring form binds only `locale`, so
55
+ * it can never collide with a `params` variable the document already declares.
56
+ * Expression-bodied arrow functions are first converted to a block so the
57
+ * declaration has somewhere to live.
56
58
  *
57
59
  * No-ops when `locale` is already bound in the function — whether as a simple
58
60
  * identifier, through a destructuring pattern (e.g.
59
- * `const { locale = defaultLocale } = useLoaderData()`), or as a function
61
+ * `const { locale = defaultLocale } = Route.useLoaderData()`), or as a function
60
62
  * parameter — so the injected declaration never collides with one the document
61
63
  * already provides (which would produce an
62
64
  * `Identifier 'locale' has already been declared` parse error).
65
+ *
66
+ * @returns `true` when the declaration was injected, `false` when the document
67
+ * already binds `locale` itself. Callers use this to skip the imports and the
68
+ * route API declaration the injected statement would have needed.
63
69
  */
64
70
  const ensureLocaleFromParams = (funcNode) => {
65
71
  if (funcNode.body?.type !== "BlockStatement") funcNode.body = b.blockStatement([b.returnStatement(funcNode.body)]);
66
72
  const declaredInBody = funcNode.body.body.some((stmt) => stmt.type === "VariableDeclaration" && stmt.declarations.some((d) => patternBindsName(d.id, "locale")));
67
73
  const declaredInParams = (funcNode.params ?? []).some((param) => patternBindsName(param, "locale"));
68
- if (declaredInBody || declaredInParams) return;
69
- const statement = parseTsx("const locale = useParams({ strict: false }).locale ?? defaultLocale;").program.body[0];
74
+ if (declaredInBody || declaredInParams) return false;
75
+ const statement = parseTsx(`const { locale = defaultLocale } = ${LOCALE_ROUTE_API_VARIABLE}.useParams();`).program.body[0];
70
76
  funcNode.body.body.unshift(statement);
77
+ return true;
71
78
  };
79
+ /**
80
+ * Ensures the module-scope `const localeRoute = getRouteApi("/<segment>");`
81
+ * declaration the injected locale statement reads from, inserted right after the
82
+ * import block.
83
+ *
84
+ * Referencing the locale route by id keeps the root document free of an import
85
+ * of `<segment>/route` — importing a child route module from `__root` is
86
+ * discouraged, since the generated route tree already imports the root.
87
+ *
88
+ * No-ops when `localeRoute` is already bound at module scope, reusing that
89
+ * binding rather than redeclaring it (which would be a parse error).
90
+ *
91
+ * @returns `true` when the declaration was inserted, `false` when an existing
92
+ * binding was reused.
93
+ */
94
+ const ensureLocaleRouteApi = (ast, localeSegment) => {
95
+ if (isModuleScopeBinding(ast, LOCALE_ROUTE_API_VARIABLE)) return false;
96
+ const declaration = parseTsx(`const ${LOCALE_ROUTE_API_VARIABLE} = getRouteApi("/${localeSegment}");`).program.body[0];
97
+ ast.program.body.splice(firstInsertIndex(ast), 0, declaration);
98
+ return true;
99
+ };
100
+ /**
101
+ * Puts a blank line between the import block and the inserted route API
102
+ * declaration — recast prints a spliced statement flush against the preceding
103
+ * line, which reads as part of the imports.
104
+ */
105
+ const separateRouteApiDeclaration = (printedCode) => printedCode.replace(new RegExp(`([^\\n])\\n(const ${LOCALE_ROUTE_API_VARIABLE} = getRouteApi\\()`), "$1\n\n$2");
72
106
  /** Sets `lang={locale}` and `dir={getHTMLTextDir(locale)}` on the first `<html>` element. */
73
107
  const setHtmlLangAndDir = (ast) => {
74
108
  recast.visit(ast, { visitJSXOpeningElement(path) {
@@ -89,12 +123,16 @@ const setHtmlLangAndDir = (ast) => {
89
123
  };
90
124
  /**
91
125
  * Wraps the `{children}` of a TanStack Start root document with
92
- * `IntlayerProvider`, deriving the locale from the `{-$locale}` route param.
126
+ * `IntlayerProvider`, deriving the locale from the locale segment route params.
93
127
  * Safe and idempotent: bails (returns the original code) when the provider is
94
128
  * already present, when no `<html>` document function is found, or when there is
95
129
  * no `{children}` placeholder to wrap.
130
+ *
131
+ * @param code Source of the project's `__root` document.
132
+ * @param localeSegment Locale segment directory in use — `{-$locale}` for every
133
+ * routing mode but `prefix-all`, which uses the required `$locale`.
96
134
  */
97
- const wrapRootWithProvider = (code) => {
135
+ const wrapRootWithProvider = (code, localeSegment) => {
98
136
  const ast = parseTsx(code);
99
137
  if (code.includes("IntlayerProvider")) return {
100
138
  code,
@@ -122,14 +160,19 @@ const wrapRootWithProvider = (code) => {
122
160
  code,
123
161
  status: "skipped"
124
162
  };
163
+ const injectedLocaleDeclaration = ensureLocaleFromParams(funcNode);
125
164
  ensureNamedImport(ast, "IntlayerProvider", "react-intlayer");
126
- ensureNamedImport(ast, "useParams", "@tanstack/react-router");
127
- ensureNamedImport(ast, "defaultLocale", "intlayer");
165
+ let insertedRouteApi = false;
166
+ if (injectedLocaleDeclaration) {
167
+ ensureNamedImport(ast, "getRouteApi", "@tanstack/react-router");
168
+ ensureNamedImport(ast, "defaultLocale", "intlayer");
169
+ insertedRouteApi = ensureLocaleRouteApi(ast, localeSegment);
170
+ }
128
171
  ensureNamedImport(ast, "getHTMLTextDir", "intlayer");
129
- ensureLocaleFromParams(funcNode);
130
172
  setHtmlLangAndDir(ast);
173
+ const printedCode = recast.print(ast).code;
131
174
  return {
132
- code: recast.print(ast).code,
175
+ code: insertedRouteApi ? separateRouteApiDeclaration(printedCode) : printedCode,
133
176
  status: "wrapped"
134
177
  };
135
178
  };
@@ -1 +1 @@
1
- {"version":3,"file":"transforms.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/transforms.ts"],"sourcesContent":["import * as recast from 'recast';\nimport { babelTsParser } from '../../../utils/babelParser';\nimport { ensureNamedImport } from '../../utils/astImports';\n\nconst { builders: b, namedTypes: n } = recast.types;\n\n/** babel-ts parser handles TypeScript *and* JSX. */\nconst parseTsx = (code: string): any =>\n recast.parse(code, { parser: babelTsParser });\n\n/** Result of a source transform. `code` is unchanged for any non-`wrapped` status. */\nexport type TransformResult = {\n code: string;\n status: 'wrapped' | 'already' | 'skipped';\n};\n\n/**\n * Finds the single function that returns the `<html>` document element. Returns\n * `null` when there is no such function, or more than one (ambiguous).\n */\nconst findHtmlDocumentFunction = (ast: any): any => {\n const found = new Set<any>();\n\n recast.visit(ast, {\n visitJSXOpeningElement(path) {\n const node = path.node;\n if (node.name?.type === 'JSXIdentifier' && node.name.name === 'html') {\n // Walk up to the nearest enclosing function node.\n let current = path.parentPath;\n while (current) {\n const value = current.value;\n if (\n value &&\n (n.FunctionDeclaration.check(value) ||\n n.FunctionExpression.check(value) ||\n n.ArrowFunctionExpression.check(value))\n ) {\n found.add(value);\n break;\n }\n current = current.parentPath;\n }\n }\n this.traverse(path);\n },\n });\n\n return found.size === 1 ? [...found][0] : null;\n};\n\n/**\n * Whether the binding pattern `node` introduces a variable named `name`.\n * Recurses through destructuring patterns so all of `const locale`,\n * `const { locale } = …`, `const { locale = fallback } = …`,\n * `const { foo: locale } = …`, `const [locale] = …` and `...locale` are\n * detected — not just a bare identifier.\n */\nconst patternBindsName = (node: any, name: string): boolean => {\n if (!node) return false;\n switch (node.type) {\n case 'Identifier':\n return node.name === name;\n case 'AssignmentPattern':\n // `locale = fallback`\n return patternBindsName(node.left, name);\n case 'RestElement':\n // `...locale`\n return patternBindsName(node.argument, name);\n case 'ArrayPattern':\n return node.elements.some((element: any) =>\n patternBindsName(element, name)\n );\n case 'ObjectPattern':\n return node.properties.some((property: any) =>\n property.type === 'RestElement'\n ? patternBindsName(property.argument, name)\n : // The *value* is the binding target (`{ foo: locale }` binds `locale`).\n patternBindsName(property.value, name)\n );\n default:\n return false;\n }\n};\n\n/**\n * Inserts `const locale = …` once, at the top of the function body. A single\n * self-contained statement is used (rather than an intermediate `params` const)\n * so it can never collide with a `params` variable the document already\n * declares. Expression-bodied arrow functions are first converted to a block so\n * the declaration has somewhere to live.\n *\n * No-ops when `locale` is already bound in the function — whether as a simple\n * identifier, through a destructuring pattern (e.g.\n * `const { locale = defaultLocale } = useLoaderData()`), or as a function\n * parameter — so the injected declaration never collides with one the document\n * already provides (which would produce an\n * `Identifier 'locale' has already been declared` parse error).\n */\nconst ensureLocaleFromParams = (funcNode: any): void => {\n if (funcNode.body?.type !== 'BlockStatement') {\n funcNode.body = b.blockStatement([b.returnStatement(funcNode.body)]);\n }\n\n const declaredInBody = funcNode.body.body.some(\n (stmt: any) =>\n stmt.type === 'VariableDeclaration' &&\n stmt.declarations.some((d: any) => patternBindsName(d.id, 'locale'))\n );\n const declaredInParams = (funcNode.params ?? []).some((param: any) =>\n patternBindsName(param, 'locale')\n );\n if (declaredInBody || declaredInParams) return;\n\n const statement = parseTsx(\n 'const locale = useParams({ strict: false }).locale ?? defaultLocale;'\n ).program.body[0];\n funcNode.body.body.unshift(statement);\n};\n\n/** Sets `lang={locale}` and `dir={getHTMLTextDir(locale)}` on the first `<html>` element. */\nconst setHtmlLangAndDir = (ast: any): void => {\n recast.visit(ast, {\n visitJSXOpeningElement(path) {\n const node = path.node;\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'html') {\n this.traverse(path);\n return;\n }\n\n const upsertAttribute = (name: string, value: any): void => {\n const existing = node.attributes?.find(\n (attr: any) =>\n attr.type === 'JSXAttribute' && attr.name?.name === name\n ) as any;\n if (existing) {\n existing.value = value;\n } else {\n node.attributes?.push(b.jsxAttribute(b.jsxIdentifier(name), value));\n }\n };\n\n upsertAttribute('lang', b.jsxExpressionContainer(b.identifier('locale')));\n upsertAttribute(\n 'dir',\n b.jsxExpressionContainer(\n b.callExpression(b.identifier('getHTMLTextDir'), [\n b.identifier('locale'),\n ])\n )\n );\n return false;\n },\n });\n};\n\n/**\n * Wraps the `{children}` of a TanStack Start root document with\n * `IntlayerProvider`, deriving the locale from the `{-$locale}` route param.\n * Safe and idempotent: bails (returns the original code) when the provider is\n * already present, when no `<html>` document function is found, or when there is\n * no `{children}` placeholder to wrap.\n */\nexport const wrapRootWithProvider = (code: string): TransformResult => {\n const ast = parseTsx(code);\n\n if (code.includes('IntlayerProvider')) return { code, status: 'already' };\n\n const funcNode = findHtmlDocumentFunction(ast);\n if (!funcNode) return { code, status: 'skipped' };\n\n let wrapped = false;\n recast.visit(funcNode, {\n visitJSXExpressionContainer(path) {\n if (wrapped) return false;\n const expression = path.node.expression;\n if (expression?.type === 'Identifier' && expression.name === 'children') {\n const template = parseTsx(\n 'const __wrap = <IntlayerProvider locale={locale}>{__child__}</IntlayerProvider>;'\n );\n const providerElement = template.program.body[0].declarations[0].init;\n providerElement.children = [path.node];\n path.replace(providerElement);\n wrapped = true;\n return false;\n }\n this.traverse(path);\n },\n });\n\n if (!wrapped) return { code, status: 'skipped' };\n\n ensureNamedImport(ast, 'IntlayerProvider', 'react-intlayer');\n ensureNamedImport(ast, 'useParams', '@tanstack/react-router');\n ensureNamedImport(ast, 'defaultLocale', 'intlayer');\n ensureNamedImport(ast, 'getHTMLTextDir', 'intlayer');\n ensureLocaleFromParams(funcNode);\n setHtmlLangAndDir(ast);\n\n return { code: recast.print(ast).code, status: 'wrapped' };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"transforms.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/transforms.ts"],"sourcesContent":["import * as recast from 'recast';\nimport { babelTsParser } from '../../../utils/babelParser';\nimport {\n ensureNamedImport,\n firstInsertIndex,\n isModuleScopeBinding,\n} from '../../utils/astImports';\n\nconst { builders: b, namedTypes: n } = recast.types;\n\n/** Module-scope identifier bound to the locale route's typed API. */\nconst LOCALE_ROUTE_API_VARIABLE = 'localeRoute';\n\n/** babel-ts parser handles TypeScript *and* JSX. */\nconst parseTsx = (code: string): any =>\n recast.parse(code, { parser: babelTsParser });\n\n/** Result of a source transform. `code` is unchanged for any non-`wrapped` status. */\nexport type TransformResult = {\n code: string;\n status: 'wrapped' | 'already' | 'skipped';\n};\n\n/**\n * Finds the single function that returns the `<html>` document element. Returns\n * `null` when there is no such function, or more than one (ambiguous).\n */\nconst findHtmlDocumentFunction = (ast: any): any => {\n const found = new Set<any>();\n\n recast.visit(ast, {\n visitJSXOpeningElement(path) {\n const node = path.node;\n if (node.name?.type === 'JSXIdentifier' && node.name.name === 'html') {\n // Walk up to the nearest enclosing function node.\n let current = path.parentPath;\n while (current) {\n const value = current.value;\n if (\n value &&\n (n.FunctionDeclaration.check(value) ||\n n.FunctionExpression.check(value) ||\n n.ArrowFunctionExpression.check(value))\n ) {\n found.add(value);\n break;\n }\n current = current.parentPath;\n }\n }\n this.traverse(path);\n },\n });\n\n return found.size === 1 ? [...found][0] : null;\n};\n\n/**\n * Whether the binding pattern `node` introduces a variable named `name`.\n * Recurses through destructuring patterns so all of `const locale`,\n * `const { locale } = …`, `const { locale = fallback } = …`,\n * `const { foo: locale } = …`, `const [locale] = …` and `...locale` are\n * detected — not just a bare identifier.\n */\nconst patternBindsName = (node: any, name: string): boolean => {\n if (!node) return false;\n switch (node.type) {\n case 'Identifier':\n return node.name === name;\n case 'AssignmentPattern':\n // `locale = fallback`\n return patternBindsName(node.left, name);\n case 'RestElement':\n // `...locale`\n return patternBindsName(node.argument, name);\n case 'ArrayPattern':\n return node.elements.some((element: any) =>\n patternBindsName(element, name)\n );\n case 'ObjectPattern':\n return node.properties.some((property: any) =>\n property.type === 'RestElement'\n ? patternBindsName(property.argument, name)\n : // The *value* is the binding target (`{ foo: locale }` binds `locale`).\n patternBindsName(property.value, name)\n );\n default:\n return false;\n }\n};\n\n/**\n * Inserts `const { locale = defaultLocale } = localeRoute.useParams();` once, at\n * the top of the function body. The destructuring form binds only `locale`, so\n * it can never collide with a `params` variable the document already declares.\n * Expression-bodied arrow functions are first converted to a block so the\n * declaration has somewhere to live.\n *\n * No-ops when `locale` is already bound in the function — whether as a simple\n * identifier, through a destructuring pattern (e.g.\n * `const { locale = defaultLocale } = Route.useLoaderData()`), or as a function\n * parameter — so the injected declaration never collides with one the document\n * already provides (which would produce an\n * `Identifier 'locale' has already been declared` parse error).\n *\n * @returns `true` when the declaration was injected, `false` when the document\n * already binds `locale` itself. Callers use this to skip the imports and the\n * route API declaration the injected statement would have needed.\n */\nconst ensureLocaleFromParams = (funcNode: any): boolean => {\n if (funcNode.body?.type !== 'BlockStatement') {\n funcNode.body = b.blockStatement([b.returnStatement(funcNode.body)]);\n }\n\n const declaredInBody = funcNode.body.body.some(\n (stmt: any) =>\n stmt.type === 'VariableDeclaration' &&\n stmt.declarations.some((d: any) => patternBindsName(d.id, 'locale'))\n );\n const declaredInParams = (funcNode.params ?? []).some((param: any) =>\n patternBindsName(param, 'locale')\n );\n if (declaredInBody || declaredInParams) return false;\n\n const statement = parseTsx(\n `const { locale = defaultLocale } = ${LOCALE_ROUTE_API_VARIABLE}.useParams();`\n ).program.body[0];\n funcNode.body.body.unshift(statement);\n return true;\n};\n\n/**\n * Ensures the module-scope `const localeRoute = getRouteApi(\"/<segment>\");`\n * declaration the injected locale statement reads from, inserted right after the\n * import block.\n *\n * Referencing the locale route by id keeps the root document free of an import\n * of `<segment>/route` — importing a child route module from `__root` is\n * discouraged, since the generated route tree already imports the root.\n *\n * No-ops when `localeRoute` is already bound at module scope, reusing that\n * binding rather than redeclaring it (which would be a parse error).\n *\n * @returns `true` when the declaration was inserted, `false` when an existing\n * binding was reused.\n */\nconst ensureLocaleRouteApi = (ast: any, localeSegment: string): boolean => {\n if (isModuleScopeBinding(ast, LOCALE_ROUTE_API_VARIABLE)) return false;\n\n const declaration = parseTsx(\n `const ${LOCALE_ROUTE_API_VARIABLE} = getRouteApi(\"/${localeSegment}\");`\n ).program.body[0];\n ast.program.body.splice(firstInsertIndex(ast), 0, declaration);\n return true;\n};\n\n/**\n * Puts a blank line between the import block and the inserted route API\n * declaration — recast prints a spliced statement flush against the preceding\n * line, which reads as part of the imports.\n */\nconst separateRouteApiDeclaration = (printedCode: string): string =>\n printedCode.replace(\n new RegExp(\n `([^\\\\n])\\\\n(const ${LOCALE_ROUTE_API_VARIABLE} = getRouteApi\\\\()`\n ),\n '$1\\n\\n$2'\n );\n\n/** Sets `lang={locale}` and `dir={getHTMLTextDir(locale)}` on the first `<html>` element. */\nconst setHtmlLangAndDir = (ast: any): void => {\n recast.visit(ast, {\n visitJSXOpeningElement(path) {\n const node = path.node;\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'html') {\n this.traverse(path);\n return;\n }\n\n const upsertAttribute = (name: string, value: any): void => {\n const existing = node.attributes?.find(\n (attr: any) =>\n attr.type === 'JSXAttribute' && attr.name?.name === name\n ) as any;\n if (existing) {\n existing.value = value;\n } else {\n node.attributes?.push(b.jsxAttribute(b.jsxIdentifier(name), value));\n }\n };\n\n upsertAttribute('lang', b.jsxExpressionContainer(b.identifier('locale')));\n upsertAttribute(\n 'dir',\n b.jsxExpressionContainer(\n b.callExpression(b.identifier('getHTMLTextDir'), [\n b.identifier('locale'),\n ])\n )\n );\n return false;\n },\n });\n};\n\n/**\n * Wraps the `{children}` of a TanStack Start root document with\n * `IntlayerProvider`, deriving the locale from the locale segment route params.\n * Safe and idempotent: bails (returns the original code) when the provider is\n * already present, when no `<html>` document function is found, or when there is\n * no `{children}` placeholder to wrap.\n *\n * @param code Source of the project's `__root` document.\n * @param localeSegment Locale segment directory in use — `{-$locale}` for every\n * routing mode but `prefix-all`, which uses the required `$locale`.\n */\nexport const wrapRootWithProvider = (\n code: string,\n localeSegment: string\n): TransformResult => {\n const ast = parseTsx(code);\n\n if (code.includes('IntlayerProvider')) return { code, status: 'already' };\n\n const funcNode = findHtmlDocumentFunction(ast);\n if (!funcNode) return { code, status: 'skipped' };\n\n let wrapped = false;\n recast.visit(funcNode, {\n visitJSXExpressionContainer(path) {\n if (wrapped) return false;\n const expression = path.node.expression;\n if (expression?.type === 'Identifier' && expression.name === 'children') {\n const template = parseTsx(\n 'const __wrap = <IntlayerProvider locale={locale}>{__child__}</IntlayerProvider>;'\n );\n const providerElement = template.program.body[0].declarations[0].init;\n providerElement.children = [path.node];\n path.replace(providerElement);\n wrapped = true;\n return false;\n }\n this.traverse(path);\n },\n });\n\n if (!wrapped) return { code, status: 'skipped' };\n\n const injectedLocaleDeclaration = ensureLocaleFromParams(funcNode);\n\n ensureNamedImport(ast, 'IntlayerProvider', 'react-intlayer');\n // Only needed by the injected declaration: a document that already derives its\n // own `locale` must not be given unused imports or a stray route API const.\n let insertedRouteApi = false;\n if (injectedLocaleDeclaration) {\n ensureNamedImport(ast, 'getRouteApi', '@tanstack/react-router');\n ensureNamedImport(ast, 'defaultLocale', 'intlayer');\n insertedRouteApi = ensureLocaleRouteApi(ast, localeSegment);\n }\n ensureNamedImport(ast, 'getHTMLTextDir', 'intlayer');\n setHtmlLangAndDir(ast);\n\n const printedCode = recast.print(ast).code;\n\n return {\n code: insertedRouteApi\n ? separateRouteApiDeclaration(printedCode)\n : printedCode,\n status: 'wrapped',\n };\n};\n"],"mappings":"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"}
@@ -32,14 +32,14 @@ const DocumentationRouter = {
32
32
  ViteAndSolid: "https://intlayer.org/doc/environment/vite-and-solid.md",
33
33
  ViteAndSvelte: "https://intlayer.org/doc/environment/vite-and-svelte.md",
34
34
  ViteAndPreact: "https://intlayer.org/doc/environment/vite-and-preact.md",
35
- TanStackRouter: "https://intlayer.org/doc/environment/tanstack.md",
35
+ TanStackRouter: "https://intlayer.org/doc/environment/tanstack-start.md",
36
36
  NuxtAndVue: "https://intlayer.org/doc/environment/nuxt-and-vue.md",
37
37
  Angular: "https://intlayer.org/doc/environment/angular.md",
38
38
  SvelteKit: "https://intlayer.org/doc/environment/sveltekit.md",
39
39
  ReactNativeAndExpo: "https://intlayer.org/doc/environment/react-native-and-expo.md",
40
40
  Lynx: "https://intlayer.org/doc/environment/lynx-and-react.md",
41
41
  Express: "https://intlayer.org/doc/environment/express.md",
42
- NestJS: "https://intlayer.org/doc/environment/nestjs.md",
42
+ NestJS: "https://intlayer.org/doc/environment/nest.md",
43
43
  Fastify: "https://intlayer.org/doc/environment/fastify.md",
44
44
  Default: "https://intlayer.org/doc/get-started",
45
45
  LSP: "https://intlayer.org/doc/lsp.md",
@@ -148,7 +148,8 @@ const initIntlayer = async (rootDir, options) => {
148
148
  const linguiPresent = Boolean(effectiveAllDeps["@lingui/core"] || effectiveAllDeps["@lingui/react"] || effectiveAllDeps["@intlayer/lingui"]);
149
149
  const linguiCatalog = linguiPresent ? await detectLinguiCatalogPattern(rootDir) : null;
150
150
  const hintLinguiJson = Boolean(options?.hintDependencies?.["__lingui_json__"]);
151
- const { packagesToInstall, devPackagesToInstall, compatSyncConfig, compatVitePluginConfig } = detectMissingIntlayerPackages(effectiveAllDeps, { linguiCatalogFormat: linguiCatalog?.format ?? (linguiPresent ? hintLinguiJson ? "json" : "po" : null) });
151
+ const linguiCatalogFormat = linguiCatalog?.format ?? (linguiPresent ? hintLinguiJson ? "json" : "po" : null);
152
+ const { packagesToInstall, devPackagesToInstall, compatSyncConfig, compatVitePluginConfig } = detectMissingIntlayerPackages(effectiveAllDeps, { linguiCatalogFormat });
152
153
  const wantsJsonNamespaces = options?.contentStrategy === "json-namespaces" && !compatSyncConfig;
153
154
  if (wantsJsonNamespaces && !effectiveAllDeps["@intlayer/sync-json-plugin"] && !devPackagesToInstall.includes("@intlayer/sync-json-plugin")) devPackagesToInstall.push("@intlayer/sync-json-plugin");
154
155
  if (!options?.noInstallPackages) {
@@ -191,7 +192,8 @@ const initIntlayer = async (rootDir, options) => {
191
192
  if (!options?.noGitignore && await exists(rootDir, gitignorePath)) {
192
193
  const gitignoreContent = await readFileFromRoot(rootDir, gitignorePath);
193
194
  if (!gitignoreContent.includes("intlayer")) {
194
- await writeFileToRoot(rootDir, gitignorePath, `${gitignoreContent}\n# Intlayer\n.intlayer\n`);
195
+ const newContent = `${gitignoreContent}\n# Intlayer\n.intlayer\n`;
196
+ await writeFileToRoot(rootDir, gitignorePath, newContent);
195
197
  logger(`${v} Added ${colorizePath(".intlayer")} to ${colorizePath(gitignorePath)}`);
196
198
  } else logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);
197
199
  }
@@ -217,8 +219,10 @@ const initIntlayer = async (rootDir, options) => {
217
219
  const extensionId = "intlayer.intlayer-vs-code-extension";
218
220
  if (!options?.noVscodeExtension) try {
219
221
  let extensionsConfig = { recommendations: [] };
220
- if (await exists(rootDir, extensionsJsonPath)) extensionsConfig = parseJSONWithComments(await readFileFromRoot(rootDir, extensionsJsonPath));
221
- else await ensureDirectory(rootDir, vscodeDir);
222
+ if (await exists(rootDir, extensionsJsonPath)) {
223
+ const content = await readFileFromRoot(rootDir, extensionsJsonPath);
224
+ extensionsConfig = parseJSONWithComments(content);
225
+ } else await ensureDirectory(rootDir, vscodeDir);
222
226
  if (!extensionsConfig.recommendations) extensionsConfig.recommendations = [];
223
227
  if (!extensionsConfig.recommendations.includes(extensionId)) {
224
228
  extensionsConfig.recommendations.push(extensionId);
@@ -231,8 +235,10 @@ const initIntlayer = async (rootDir, options) => {
231
235
  const settingsJsonPath = join(vscodeDir, "settings.json");
232
236
  if (!options?.noLsp) try {
233
237
  let settingsConfig = {};
234
- if (await exists(rootDir, settingsJsonPath)) settingsConfig = parseJSONWithComments(await readFileFromRoot(rootDir, settingsJsonPath));
235
- else await ensureDirectory(rootDir, vscodeDir);
238
+ if (await exists(rootDir, settingsJsonPath)) {
239
+ const content = await readFileFromRoot(rootDir, settingsJsonPath);
240
+ settingsConfig = parseJSONWithComments(content);
241
+ } else await ensureDirectory(rootDir, vscodeDir);
236
242
  let settingsUpdated = false;
237
243
  if (!settingsConfig["intlayer.languageServer.command"]) {
238
244
  settingsConfig["intlayer.languageServer.command"] = "npx";
@@ -254,7 +260,8 @@ const initIntlayer = async (rootDir, options) => {
254
260
  for (const fileName of tsConfigFiles) if (await exists(rootDir, fileName)) {
255
261
  hasTsConfig = true;
256
262
  try {
257
- const config = parseJSONWithComments(await readFileFromRoot(rootDir, fileName));
263
+ const fileContent = await readFileFromRoot(rootDir, fileName);
264
+ const config = parseJSONWithComments(fileContent);
258
265
  const typeDefinition = "./.intlayer/**/*.ts";
259
266
  let updated = false;
260
267
  if (!config.include) {} else if (Array.isArray(config.include) && !config.include.some((pattern) => pattern.includes(".intlayer"))) {
@@ -298,7 +305,9 @@ const initIntlayer = async (rootDir, options) => {
298
305
  ]) if (await exists(rootDir, configFile)) {
299
306
  const configContent = await readFileFromRoot(rootDir, configFile);
300
307
  if (!configContent.includes(syncPluginPackage)) {
301
- await writeFileToRoot(rootDir, configFile, updateIntlayerConfigWithSyncPlugin(configContent, configFile.split(".").pop(), resolvedSyncConfig));
308
+ const extension = configFile.split(".").pop();
309
+ const updatedConfigContent = updateIntlayerConfigWithSyncPlugin(configContent, extension, resolvedSyncConfig);
310
+ await writeFileToRoot(rootDir, configFile, updatedConfigContent);
302
311
  logger(`${v} Updated ${colorizePath(configFile)} with ${syncPluginName} compat plugin`);
303
312
  } else logger(`${v} ${colorizePath(configFile)} already includes ${syncPluginName} plugin`);
304
313
  break;
@@ -318,15 +327,18 @@ const initIntlayer = async (rootDir, options) => {
318
327
  const { replacesVitePlugin } = compatVitePluginConfig;
319
328
  if (content.includes(compatVitePluginConfig.pluginPackageSource)) logger(`${v} ${colorizePath(file)} already includes ${compatVitePluginConfig.pluginPackageSource}`);
320
329
  else if (replacesVitePlugin && content.includes(replacesVitePlugin.fromPackageSource)) {
321
- await writeFileToRoot(rootDir, file, replaceViteConfigPluginImportSource(content, replacesVitePlugin.importName, replacesVitePlugin.fromPackageSource, compatVitePluginConfig.pluginPackageSource));
330
+ const updatedContent = replaceViteConfigPluginImportSource(content, replacesVitePlugin.importName, replacesVitePlugin.fromPackageSource, compatVitePluginConfig.pluginPackageSource);
331
+ await writeFileToRoot(rootDir, file, updatedContent);
322
332
  logger(`${v} Updated ${colorizePath(file)} to import ${replacesVitePlugin.importName} from ${compatVitePluginConfig.pluginPackageSource}`);
323
333
  } else {
324
- await writeFileToRoot(rootDir, file, updateViteConfigForCompatPlugin(content, extension, compatVitePluginConfig));
334
+ const updatedContent = updateViteConfigForCompatPlugin(content, extension, compatVitePluginConfig);
335
+ await writeFileToRoot(rootDir, file, updatedContent);
325
336
  logger(`${v} Updated ${colorizePath(file)} to include ${compatVitePluginConfig.pluginFunctionName} compat plugin`);
326
337
  }
327
338
  } else if (hasIntlayerVitePlugin(content)) logger(`${v} ${colorizePath(file)} already includes an Intlayer plugin`);
328
339
  else {
329
- await writeFileToRoot(rootDir, file, updateViteConfig(content, extension));
340
+ const updatedContent = updateViteConfig(content, extension);
341
+ await writeFileToRoot(rootDir, file, updatedContent);
330
342
  logger(`${v} Updated ${colorizePath(file)} to include Intlayer plugin`);
331
343
  }
332
344
  break;
@@ -342,20 +354,27 @@ const initIntlayer = async (rootDir, options) => {
342
354
  hasAliasConfiguration = true;
343
355
  const content = await readFileFromRoot(rootDir, file);
344
356
  const extension = file.split(".").pop();
345
- if (allDeps["next-i18next"]) if (!content.includes("@intlayer/next-i18next")) {
346
- await writeFileToRoot(rootDir, file, updateNextConfigForNextI18next(content, extension));
347
- logger(`${v} Updated ${colorizePath(file)} to include Intlayer next-i18next compat plugin`);
348
- } else logger(`${v} ${colorizePath(file)} already includes @intlayer/next-i18next`);
349
- else if (allDeps["next-intl"]) if (!content.includes("@intlayer/next-intl/plugin")) {
350
- await writeFileToRoot(rootDir, file, updateNextConfigForNextIntl(content, extension));
351
- logger(`${v} Updated ${colorizePath(file)} to include Intlayer next-intl compat plugin`);
352
- } else logger(`${v} ${colorizePath(file)} already includes @intlayer/next-intl/plugin`);
353
- else if (allDeps["next-translate"]) if (!content.includes("@intlayer/next-translate")) {
354
- await writeFileToRoot(rootDir, file, updateNextConfigForNextTranslate(content, extension));
355
- logger(`${v} Updated ${colorizePath(file)} to include Intlayer next-translate compat plugin`);
356
- } else logger(`${v} ${colorizePath(file)} already includes @intlayer/next-translate`);
357
- else if (!content.includes("next-intlayer")) {
358
- await writeFileToRoot(rootDir, file, updateNextConfig(content, extension));
357
+ if (allDeps["next-i18next"]) {
358
+ if (!content.includes("@intlayer/next-i18next")) {
359
+ const updatedContent = updateNextConfigForNextI18next(content, extension);
360
+ await writeFileToRoot(rootDir, file, updatedContent);
361
+ logger(`${v} Updated ${colorizePath(file)} to include Intlayer next-i18next compat plugin`);
362
+ } else logger(`${v} ${colorizePath(file)} already includes @intlayer/next-i18next`);
363
+ } else if (allDeps["next-intl"]) {
364
+ if (!content.includes("@intlayer/next-intl/plugin")) {
365
+ const updatedContent = updateNextConfigForNextIntl(content, extension);
366
+ await writeFileToRoot(rootDir, file, updatedContent);
367
+ logger(`${v} Updated ${colorizePath(file)} to include Intlayer next-intl compat plugin`);
368
+ } else logger(`${v} ${colorizePath(file)} already includes @intlayer/next-intl/plugin`);
369
+ } else if (allDeps["next-translate"]) {
370
+ if (!content.includes("@intlayer/next-translate")) {
371
+ const updatedContent = updateNextConfigForNextTranslate(content, extension);
372
+ await writeFileToRoot(rootDir, file, updatedContent);
373
+ logger(`${v} Updated ${colorizePath(file)} to include Intlayer next-translate compat plugin`);
374
+ } else logger(`${v} ${colorizePath(file)} already includes @intlayer/next-translate`);
375
+ } else if (!content.includes("next-intlayer")) {
376
+ const updatedContent = updateNextConfig(content, extension);
377
+ await writeFileToRoot(rootDir, file, updatedContent);
359
378
  logger(`${v} Updated ${colorizePath(file)} to include Intlayer plugin`);
360
379
  }
361
380
  break;
@@ -376,7 +395,9 @@ const initIntlayer = async (rootDir, options) => {
376
395
  if (file.startsWith("astro.config.")) {
377
396
  const content = await readFileFromRoot(rootDir, file);
378
397
  if (!content.includes("astro-intlayer")) {
379
- await writeFileToRoot(rootDir, file, updateAstroConfig(content, file.split(".").pop()));
398
+ const extension = file.split(".").pop();
399
+ const updatedContent = updateAstroConfig(content, extension);
400
+ await writeFileToRoot(rootDir, file, updatedContent);
380
401
  logger(`${v} Updated ${colorizePath(file)} to include Intlayer integration`);
381
402
  }
382
403
  }
@@ -385,12 +406,15 @@ const initIntlayer = async (rootDir, options) => {
385
406
  for (const file of ["nuxt.config.js", "nuxt.config.ts"]) if (await exists(rootDir, file)) {
386
407
  hasAliasConfiguration = true;
387
408
  const content = await readFileFromRoot(rootDir, file);
388
- if (allDeps["@nuxtjs/i18n"]) if (!content.includes("@intlayer/nuxtjs-i18n")) {
389
- await writeFileToRoot(rootDir, file, updateNuxtConfigForNuxtjsI18n(content));
390
- logger(`${v} Updated ${colorizePath(file)} to include @intlayer/nuxtjs-i18n module`);
391
- } else logger(`${v} ${colorizePath(file)} already includes @intlayer/nuxtjs-i18n`);
392
- else if (!content.includes("nuxt-intlayer")) {
393
- await writeFileToRoot(rootDir, file, updateNuxtConfig(content));
409
+ if (allDeps["@nuxtjs/i18n"]) {
410
+ if (!content.includes("@intlayer/nuxtjs-i18n")) {
411
+ const updatedContent = updateNuxtConfigForNuxtjsI18n(content);
412
+ await writeFileToRoot(rootDir, file, updatedContent);
413
+ logger(`${v} Updated ${colorizePath(file)} to include @intlayer/nuxtjs-i18n module`);
414
+ } else logger(`${v} ${colorizePath(file)} already includes @intlayer/nuxtjs-i18n`);
415
+ } else if (!content.includes("nuxt-intlayer")) {
416
+ const updatedContent = updateNuxtConfig(content);
417
+ await writeFileToRoot(rootDir, file, updatedContent);
394
418
  logger(`${v} Updated ${colorizePath(file)} to include Intlayer module`);
395
419
  }
396
420
  break;
@@ -412,7 +436,8 @@ const initIntlayer = async (rootDir, options) => {
412
436
  const content = await readFileFromRoot(rootDir, metroConfigFile);
413
437
  if (content.includes("react-native-intlayer")) logger(`${v} ${colorizePath(metroConfigFile)} already includes the Intlayer Metro plugin`);
414
438
  else {
415
- const updatedContent = updateMetroConfig(content, metroConfigFile.split(".").pop());
439
+ const extension = metroConfigFile.split(".").pop();
440
+ const updatedContent = updateMetroConfig(content, extension);
416
441
  if (updatedContent !== content) {
417
442
  await writeFileToRoot(rootDir, metroConfigFile, updatedContent);
418
443
  logger(`${v} Updated ${colorizePath(metroConfigFile)} to include the Intlayer Metro plugin`);
@@ -456,11 +481,13 @@ const initIntlayer = async (rootDir, options) => {
456
481
  ...backendIntlayerPackages
457
482
  ].some((pkg) => allDeps[pkg])) hasAliasConfiguration = true;
458
483
  if (!hasAliasConfiguration) {
459
- const aliases = getAlias({ configuration: getConfiguration({ baseDir: rootDir }) });
484
+ const configuration = getConfiguration({ baseDir: rootDir });
485
+ const aliases = getAlias({ configuration });
460
486
  if (hasTsConfig && tsConfigFiles.length > 0) {
461
487
  const tsConfigPath = tsConfigFiles.find((file) => file === "tsconfig.json") || tsConfigFiles[0];
462
488
  if (tsConfigPath) {
463
- const config = parseJSONWithComments(await readFileFromRoot(rootDir, tsConfigPath));
489
+ const tsConfigContent = await readFileFromRoot(rootDir, tsConfigPath);
490
+ const config = parseJSONWithComments(tsConfigContent);
464
491
  config.compilerOptions ??= {};
465
492
  config.compilerOptions.paths ??= {};
466
493
  let updated = false;
@@ -478,7 +505,8 @@ const initIntlayer = async (rootDir, options) => {
478
505
  } else {
479
506
  const jsConfigPath = "jsconfig.json";
480
507
  if (await exists(rootDir, jsConfigPath)) {
481
- const config = parseJSONWithComments(await readFileFromRoot(rootDir, jsConfigPath));
508
+ const jsConfigContent = await readFileFromRoot(rootDir, jsConfigPath);
509
+ const config = parseJSONWithComments(jsConfigContent);
482
510
  config.compilerOptions ??= {};
483
511
  config.compilerOptions.paths ??= {};
484
512
  let updated = false;