fimo 0.7.0-experimental.3 → 0.7.0-experimental.5

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 (412) hide show
  1. package/README.md +2 -3
  2. package/assets/content-templates/hooks-template.eta +27 -73
  3. package/assets/content-templates/types-template.eta +1 -4
  4. package/assets/skills/fimo/SKILL.md +3 -3
  5. package/assets/skills/fimo/references/assets.md +2 -2
  6. package/assets/skills/fimo/references/content.md +43 -47
  7. package/assets/skills/fimo/references/design.md +1 -1
  8. package/assets/skills/fimo/references/locales.md +0 -8
  9. package/assets/skills/fimo/references/setup-react-router.md +2 -2
  10. package/assets/skills/fimo/references/ui.md +1 -1
  11. package/assets/skills/fimo-cli/SKILL.md +1 -1
  12. package/assets/skills/fimo-cli/references/assets.md +24 -7
  13. package/assets/skills/fimo-cli/references/content.md +16 -19
  14. package/assets/skills/fimo-cli/references/domains.md +1 -1
  15. package/assets/skills/fimo-cli/references/locales.md +0 -6
  16. package/assets/skills/fimo-cli/references/media.md +142 -132
  17. package/assets/skills/fimo-migration/SKILL.md +22 -2
  18. package/assets/skills/fimo-migration/references/content.md +8 -0
  19. package/assets/skills/fimo-migration/references/manifest.md +35 -0
  20. package/assets/skills/fimo-migration/references/qa.md +24 -2
  21. package/assets/skills/fimo-migration/references/workflow.md +12 -1
  22. package/assets/skills/fimo-migration/references/wrap.md +582 -0
  23. package/assets/skills/fimo-studio/references/custom-domains.md +1 -1
  24. package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
  25. package/dist/build/vite/index.d.ts.map +1 -0
  26. package/dist/build/vite/plugins/content-sync.d.ts.map +1 -0
  27. package/dist/build/vite/plugins/content-sync.test.d.ts +2 -0
  28. package/dist/build/vite/plugins/content-sync.test.d.ts.map +1 -0
  29. package/dist/build/vite/plugins/content-sync.test.js +64 -0
  30. package/dist/build/vite/plugins/data-id.d.ts.map +1 -0
  31. package/dist/build/vite/plugins/fimo-config.d.ts.map +1 -0
  32. package/dist/build/vite/plugins/fimo-config.test.d.ts +2 -0
  33. package/dist/build/vite/plugins/fimo-config.test.d.ts.map +1 -0
  34. package/dist/build/vite/plugins/fimo-config.test.js +46 -0
  35. package/dist/build/vite/plugins/overlay.d.ts.map +1 -0
  36. package/dist/build/vite/plugins/robots.d.ts.map +1 -0
  37. package/dist/build/vite/plugins/seo.d.ts.map +1 -0
  38. package/dist/build/vite/plugins/server-config.d.ts.map +1 -0
  39. package/dist/build/vite/plugins/sitemap.d.ts.map +1 -0
  40. package/dist/build/vite/plugins/translations.d.ts +2 -8
  41. package/dist/build/vite/plugins/translations.d.ts.map +1 -0
  42. package/dist/build/vite/plugins/translations.js +3 -121
  43. package/dist/build/vite/plugins/translations.test.d.ts +2 -0
  44. package/dist/build/vite/plugins/translations.test.d.ts.map +1 -0
  45. package/dist/build/vite/plugins/translations.test.js +266 -0
  46. package/dist/cli/bundle.json +2 -3
  47. package/dist/cli/index.js +118296 -1186
  48. package/dist/runtime/app/FimoProviders.d.ts +1 -11
  49. package/dist/runtime/app/FimoProviders.d.ts.map +1 -0
  50. package/dist/runtime/app/FimoProviders.js +2 -23
  51. package/dist/runtime/app/FimoScripts.d.ts.map +1 -0
  52. package/dist/runtime/app/index.d.ts.map +1 -0
  53. package/dist/runtime/app/prefetch.d.ts.map +1 -0
  54. package/dist/runtime/astro/index.d.ts +2 -0
  55. package/dist/runtime/astro/index.d.ts.map +1 -0
  56. package/dist/runtime/astro/index.js +3 -0
  57. package/dist/runtime/astro/server.d.ts +3 -0
  58. package/dist/runtime/astro/server.d.ts.map +1 -0
  59. package/dist/runtime/astro/server.js +6 -0
  60. package/dist/runtime/content/DataSourcesProvider.d.ts.map +1 -0
  61. package/dist/runtime/content/RefreshContentProvider.d.ts.map +1 -0
  62. package/dist/runtime/content/RefreshContentProvider.test.d.ts +2 -0
  63. package/dist/runtime/content/RefreshContentProvider.test.d.ts.map +1 -0
  64. package/dist/runtime/content/RefreshContentProvider.test.js +33 -0
  65. package/dist/runtime/content/parseCollectionResponse.d.ts.map +1 -0
  66. package/dist/runtime/content/parseCollectionResponse.test.d.ts +2 -0
  67. package/dist/runtime/content/parseCollectionResponse.test.d.ts.map +1 -0
  68. package/dist/runtime/content/parseCollectionResponse.test.js +20 -0
  69. package/dist/runtime/content/utils/retrieve-data-sources.d.ts +0 -1
  70. package/dist/runtime/content/utils/retrieve-data-sources.d.ts.map +1 -0
  71. package/dist/runtime/content/utils/retrieve-data-sources.js +4 -27
  72. package/dist/runtime/core/AppErrorBoundary.d.ts.map +1 -0
  73. package/dist/runtime/core/ViteLifecycles.d.ts.map +1 -0
  74. package/dist/runtime/i18n/FimoLocaleContext.d.ts.map +1 -0
  75. package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
  76. package/dist/runtime/i18n/locale.d.ts.map +1 -0
  77. package/dist/runtime/i18n/locale.test.d.ts +2 -0
  78. package/dist/runtime/i18n/locale.test.d.ts.map +1 -0
  79. package/dist/runtime/i18n/locale.test.js +58 -0
  80. package/dist/runtime/iframe/ConsoleErrorProvider.d.ts.map +1 -0
  81. package/dist/runtime/iframe/ScreenshotProvider.d.ts.map +1 -0
  82. package/dist/runtime/iframe/runtime/overlay-hmr.d.ts.map +1 -0
  83. package/dist/runtime/iframe/runtime/overlay-hmr.js +0 -3
  84. package/dist/runtime/iframe/runtime/overlay-runtime.d.ts.map +1 -0
  85. package/dist/runtime/index.d.ts +0 -3
  86. package/dist/runtime/index.d.ts.map +1 -0
  87. package/dist/runtime/index.js +0 -2
  88. package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
  89. package/dist/runtime/next/FimoNextProviders.d.ts.map +1 -0
  90. package/dist/runtime/next/FimoNextProviders.js +20 -0
  91. package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
  92. package/dist/runtime/next/FimoNextScripts.d.ts.map +1 -0
  93. package/dist/runtime/next/FimoNextScripts.js +19 -0
  94. package/dist/runtime/next/index.d.ts +14 -0
  95. package/dist/runtime/next/index.d.ts.map +1 -0
  96. package/dist/runtime/next/index.js +14 -0
  97. package/dist/runtime/next/server.d.ts +2 -0
  98. package/dist/runtime/next/server.d.ts.map +1 -0
  99. package/dist/runtime/next/server.js +4 -0
  100. package/dist/runtime/nuxt/composables.d.ts +9 -0
  101. package/dist/runtime/nuxt/composables.d.ts.map +1 -0
  102. package/dist/runtime/nuxt/composables.js +57 -0
  103. package/dist/runtime/nuxt/index.d.ts +3 -0
  104. package/dist/runtime/nuxt/index.d.ts.map +1 -0
  105. package/dist/runtime/nuxt/index.js +6 -0
  106. package/dist/runtime/nuxt/server.d.ts +3 -0
  107. package/dist/runtime/nuxt/server.d.ts.map +1 -0
  108. package/dist/runtime/nuxt/server.js +6 -0
  109. package/dist/runtime/paths/get-fimo-paths.d.ts.map +1 -0
  110. package/dist/runtime/paths/get-fimo-paths.js +5 -15
  111. package/dist/runtime/paths/index.d.ts.map +1 -0
  112. package/dist/runtime/paths/types.d.ts.map +1 -0
  113. package/dist/runtime/primitives/components/Boolean.d.ts.map +1 -0
  114. package/dist/runtime/primitives/components/Date.d.ts.map +1 -0
  115. package/dist/runtime/primitives/components/Image.d.ts.map +1 -0
  116. package/dist/runtime/primitives/components/RichText.d.ts.map +1 -0
  117. package/dist/runtime/primitives/components/StaticImage.d.ts.map +1 -0
  118. package/dist/runtime/primitives/components/Text.d.ts.map +1 -0
  119. package/dist/runtime/primitives/components/Video.d.ts.map +1 -0
  120. package/dist/runtime/primitives/components/index.d.ts.map +1 -0
  121. package/dist/runtime/primitives/index.d.ts.map +1 -0
  122. package/dist/runtime/primitives/labels-hook.d.ts +33 -0
  123. package/dist/runtime/primitives/labels-hook.d.ts.map +1 -0
  124. package/dist/runtime/primitives/labels-hook.js +41 -0
  125. package/dist/runtime/primitives/labels-store.d.ts +12 -0
  126. package/dist/runtime/primitives/labels-store.d.ts.map +1 -0
  127. package/dist/runtime/primitives/labels-store.js +60 -0
  128. package/dist/runtime/primitives/labels-store.test.d.ts +2 -0
  129. package/dist/runtime/primitives/labels-store.test.d.ts.map +1 -0
  130. package/dist/runtime/primitives/labels-store.test.js +66 -0
  131. package/dist/runtime/primitives/lib/image-optimization.d.ts.map +1 -0
  132. package/dist/runtime/primitives/lib/index.d.ts.map +1 -0
  133. package/dist/runtime/primitives/lib/primitives.d.ts +2 -2
  134. package/dist/runtime/primitives/lib/primitives.d.ts.map +1 -0
  135. package/dist/runtime/primitives/lib/query.d.ts +3 -5
  136. package/dist/runtime/primitives/lib/query.d.ts.map +1 -0
  137. package/dist/runtime/primitives/lib/template.d.ts.map +1 -0
  138. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
  139. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts.map +1 -0
  140. package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
  141. package/dist/runtime/primitives/public-surface.test.d.ts +2 -0
  142. package/dist/runtime/primitives/public-surface.test.d.ts.map +1 -0
  143. package/dist/runtime/primitives/public-surface.test.js +45 -0
  144. package/dist/runtime/primitives/translations.d.ts +1 -27
  145. package/dist/runtime/primitives/translations.d.ts.map +1 -0
  146. package/dist/runtime/primitives/translations.js +7 -85
  147. package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
  148. package/dist/runtime/react/FimoSpaProviders.d.ts.map +1 -0
  149. package/dist/runtime/react/FimoSpaProviders.js +63 -0
  150. package/dist/runtime/react/index.d.ts +33 -0
  151. package/dist/runtime/react/index.d.ts.map +1 -0
  152. package/dist/runtime/react/index.js +39 -0
  153. package/dist/runtime/react-router/index.d.ts.map +1 -0
  154. package/dist/runtime/react-router/navigation-utils.d.ts.map +1 -0
  155. package/dist/runtime/react-router/navigation.d.ts.map +1 -0
  156. package/dist/runtime/react-router/navigation.test.d.ts +2 -0
  157. package/dist/runtime/react-router/navigation.test.d.ts.map +1 -0
  158. package/dist/runtime/react-router/navigation.test.js +35 -0
  159. package/dist/runtime/react-router/routes.d.ts.map +1 -0
  160. package/dist/runtime/react-router/routes.test.d.ts +2 -0
  161. package/dist/runtime/react-router/routes.test.d.ts.map +1 -0
  162. package/dist/runtime/react-router/routes.test.js +67 -0
  163. package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
  164. package/dist/runtime/remix/FimoRemixProviders.d.ts.map +1 -0
  165. package/dist/runtime/remix/FimoRemixProviders.js +12 -0
  166. package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
  167. package/dist/runtime/remix/FimoRemixScripts.d.ts.map +1 -0
  168. package/dist/runtime/remix/FimoRemixScripts.js +19 -0
  169. package/dist/runtime/remix/index.d.ts +12 -0
  170. package/dist/runtime/remix/index.d.ts.map +1 -0
  171. package/dist/runtime/remix/index.js +11 -0
  172. package/dist/runtime/remix/server.d.ts +2 -0
  173. package/dist/runtime/remix/server.d.ts.map +1 -0
  174. package/dist/runtime/remix/server.js +2 -0
  175. package/dist/runtime/routing/AppResetScrollOnNavigate.d.ts.map +1 -0
  176. package/dist/runtime/routing/AppRoutesProvider.d.ts.map +1 -0
  177. package/dist/runtime/seo/buildSeoForPath.d.ts +3 -1
  178. package/dist/runtime/seo/buildSeoForPath.d.ts.map +1 -0
  179. package/dist/runtime/seo/buildSeoForPath.js +1 -4
  180. package/dist/runtime/seo/htmlProps.d.ts.map +1 -0
  181. package/dist/runtime/seo/index.d.ts.map +1 -0
  182. package/dist/runtime/seo/resolver.d.ts.map +1 -0
  183. package/dist/runtime/shared/display-routes.d.ts +14 -0
  184. package/dist/runtime/shared/display-routes.d.ts.map +1 -0
  185. package/dist/runtime/shared/display-routes.js +25 -0
  186. package/dist/runtime/shared/fimo-config.server.d.ts.map +1 -0
  187. package/dist/runtime/shared/fimo-config.server.js +1 -0
  188. package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
  189. package/dist/runtime/shared/fimo-config.types.d.ts.map +1 -0
  190. package/dist/runtime/shared/i18n-messages.d.ts +29 -0
  191. package/dist/runtime/shared/i18n-messages.d.ts.map +1 -0
  192. package/dist/runtime/shared/i18n-messages.js +79 -0
  193. package/dist/runtime/shared/i18n-messages.test.d.ts +2 -0
  194. package/dist/runtime/shared/i18n-messages.test.d.ts.map +1 -0
  195. package/dist/runtime/shared/i18n-messages.test.js +39 -0
  196. package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
  197. package/dist/runtime/shared/labels-fetch.pure.d.ts.map +1 -0
  198. package/dist/runtime/shared/labels-fetch.pure.js +71 -0
  199. package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
  200. package/dist/runtime/shared/labels-fetch.server.d.ts.map +1 -0
  201. package/dist/runtime/shared/labels-fetch.server.js +97 -0
  202. package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
  203. package/dist/runtime/shared/labels-t.pure.d.ts.map +1 -0
  204. package/dist/runtime/shared/labels-t.pure.js +10 -0
  205. package/dist/runtime/strapi/client.d.ts +26 -0
  206. package/dist/runtime/strapi/client.d.ts.map +1 -0
  207. package/dist/runtime/strapi/client.js +88 -0
  208. package/dist/runtime/strapi/client.test.d.ts +2 -0
  209. package/dist/runtime/strapi/client.test.d.ts.map +1 -0
  210. package/dist/runtime/strapi/client.test.js +64 -0
  211. package/dist/runtime/strapi/index.d.ts +5 -0
  212. package/dist/runtime/strapi/index.d.ts.map +1 -0
  213. package/dist/runtime/strapi/index.js +6 -0
  214. package/dist/runtime/strapi/reshape.d.ts +28 -0
  215. package/dist/runtime/strapi/reshape.d.ts.map +1 -0
  216. package/dist/runtime/strapi/reshape.js +79 -0
  217. package/dist/runtime/strapi/reshape.test.d.ts +2 -0
  218. package/dist/runtime/strapi/reshape.test.d.ts.map +1 -0
  219. package/dist/runtime/strapi/reshape.test.js +33 -0
  220. package/dist/runtime/svelte/index.d.ts +3 -0
  221. package/dist/runtime/svelte/index.d.ts.map +1 -0
  222. package/dist/runtime/svelte/index.js +7 -0
  223. package/dist/runtime/svelte/server.d.ts +3 -0
  224. package/dist/runtime/svelte/server.d.ts.map +1 -0
  225. package/dist/runtime/svelte/server.js +6 -0
  226. package/dist/runtime/t/OptionalTracking.d.ts.map +1 -0
  227. package/dist/runtime/t/OptionalTracking.test.d.ts +2 -0
  228. package/dist/runtime/t/OptionalTracking.test.d.ts.map +1 -0
  229. package/dist/runtime/t/OptionalTracking.test.js +11 -0
  230. package/dist/runtime/t/Pageview.d.ts.map +1 -0
  231. package/dist/runtime/templates.d.ts.map +1 -0
  232. package/dist/runtime/vue/index.d.ts +3 -0
  233. package/dist/runtime/vue/index.d.ts.map +1 -0
  234. package/dist/runtime/vue/index.js +5 -0
  235. package/dist/runtime/vue/server.d.ts +3 -0
  236. package/dist/runtime/vue/server.d.ts.map +1 -0
  237. package/dist/runtime/vue/server.js +6 -0
  238. package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
  239. package/dist/runtime/wrapped/FimoFileLink.d.ts.map +1 -0
  240. package/dist/runtime/wrapped/FimoFileLink.js +19 -0
  241. package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
  242. package/dist/runtime/wrapped/FimoMediaImage.d.ts.map +1 -0
  243. package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
  244. package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
  245. package/dist/runtime/wrapped/FimoMediaVideo.d.ts.map +1 -0
  246. package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
  247. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +23 -0
  248. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts.map +1 -0
  249. package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
  250. package/dist/runtime/wrapped/FimoText.d.ts +22 -0
  251. package/dist/runtime/wrapped/FimoText.d.ts.map +1 -0
  252. package/dist/runtime/wrapped/FimoText.js +20 -0
  253. package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
  254. package/dist/runtime/wrapped/WrappedContentContext.d.ts.map +1 -0
  255. package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
  256. package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
  257. package/dist/runtime/wrapped/WrappedProviders.d.ts.map +1 -0
  258. package/dist/runtime/wrapped/WrappedProviders.js +101 -0
  259. package/dist/runtime/wrapped/dom.d.ts +4 -0
  260. package/dist/runtime/wrapped/dom.d.ts.map +1 -0
  261. package/dist/runtime/wrapped/dom.js +23 -0
  262. package/dist/runtime/wrapped/dom.test.d.ts +2 -0
  263. package/dist/runtime/wrapped/dom.test.d.ts.map +1 -0
  264. package/dist/runtime/wrapped/dom.test.js +16 -0
  265. package/dist/runtime/wrapped/server.d.ts +77 -0
  266. package/dist/runtime/wrapped/server.d.ts.map +1 -0
  267. package/dist/runtime/wrapped/server.js +237 -0
  268. package/dist/runtime/wrapped/server.test.d.ts +2 -0
  269. package/dist/runtime/wrapped/server.test.d.ts.map +1 -0
  270. package/dist/runtime/wrapped/server.test.js +91 -0
  271. package/dist/scripts/apply-wrap-templates.d.ts +61 -0
  272. package/dist/scripts/apply-wrap-templates.js +132 -0
  273. package/dist/scripts/apply-wrap-templates.test.js +199 -0
  274. package/dist/scripts/apply-wrap.d.ts +46 -0
  275. package/dist/scripts/apply-wrap.js +278 -0
  276. package/dist/scripts/apply-wrap.test.d.ts +1 -0
  277. package/dist/scripts/apply-wrap.test.js +226 -0
  278. package/dist/scripts/cms/discover.d.ts +2 -0
  279. package/dist/scripts/cms/discover.js +17 -0
  280. package/dist/scripts/cms/example-content.d.ts +32 -0
  281. package/dist/scripts/cms/example-content.js +108 -0
  282. package/dist/scripts/cms/example-content.test.d.ts +1 -0
  283. package/dist/scripts/cms/example-content.test.js +66 -0
  284. package/dist/scripts/cms/strapi/detect.d.ts +2 -0
  285. package/dist/scripts/cms/strapi/detect.js +186 -0
  286. package/dist/scripts/cms/strapi/detect.test.d.ts +1 -0
  287. package/dist/scripts/cms/strapi/detect.test.js +56 -0
  288. package/dist/scripts/cms/strapi/index.d.ts +3 -0
  289. package/dist/scripts/cms/strapi/index.js +23 -0
  290. package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
  291. package/dist/scripts/cms/strapi/list-source.js +90 -0
  292. package/dist/scripts/cms/strapi/list-source.test.d.ts +1 -0
  293. package/dist/scripts/cms/strapi/list-source.test.js +33 -0
  294. package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
  295. package/dist/scripts/cms/strapi/schema-map.js +149 -0
  296. package/dist/scripts/cms/strapi/schema-map.test.d.ts +1 -0
  297. package/dist/scripts/cms/strapi/schema-map.test.js +91 -0
  298. package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
  299. package/dist/scripts/cms/strapi/wire-client.js +107 -0
  300. package/dist/scripts/cms/strapi/wire-client.test.d.ts +1 -0
  301. package/dist/scripts/cms/strapi/wire-client.test.js +51 -0
  302. package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
  303. package/dist/scripts/cms/strapi/wiring.js +36 -0
  304. package/dist/scripts/cms/strapi/wiring.test.d.ts +1 -0
  305. package/dist/scripts/cms/strapi/wiring.test.js +27 -0
  306. package/dist/scripts/cms/types.d.ts +94 -0
  307. package/dist/scripts/cms/types.js +11 -0
  308. package/dist/scripts/detect-framework.d.ts +39 -0
  309. package/dist/scripts/detect-framework.js +133 -0
  310. package/dist/scripts/detect-framework.test.d.ts +1 -0
  311. package/dist/scripts/detect-framework.test.js +122 -0
  312. package/dist/scripts/draft-rows.d.ts +19 -0
  313. package/dist/scripts/draft-rows.js +135 -0
  314. package/dist/scripts/draft-rows.test.d.ts +1 -0
  315. package/dist/scripts/draft-rows.test.js +113 -0
  316. package/dist/scripts/draft-schemas.d.ts +27 -0
  317. package/dist/scripts/draft-schemas.js +188 -0
  318. package/dist/scripts/draft-schemas.test.d.ts +1 -0
  319. package/dist/scripts/draft-schemas.test.js +152 -0
  320. package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
  321. package/dist/scripts/frameworks/astro/routes.js +55 -0
  322. package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
  323. package/dist/scripts/frameworks/astro/template-style.js +19 -0
  324. package/dist/scripts/frameworks/discover.d.ts +70 -0
  325. package/dist/scripts/frameworks/discover.js +171 -0
  326. package/dist/scripts/frameworks/next/rewire.d.ts +30 -0
  327. package/dist/scripts/frameworks/next/rewire.js +258 -0
  328. package/dist/scripts/frameworks/next/rewire.test.d.ts +1 -0
  329. package/dist/scripts/frameworks/next/rewire.test.js +134 -0
  330. package/dist/scripts/frameworks/next/routes.d.ts +17 -0
  331. package/dist/scripts/frameworks/next/routes.js +134 -0
  332. package/dist/scripts/frameworks/next/routes.test.d.ts +1 -0
  333. package/dist/scripts/frameworks/next/routes.test.js +64 -0
  334. package/dist/scripts/frameworks/next/wiring.d.ts +26 -0
  335. package/dist/scripts/frameworks/next/wiring.js +163 -0
  336. package/dist/scripts/frameworks/next/wiring.test.d.ts +1 -0
  337. package/dist/scripts/frameworks/next/wiring.test.js +146 -0
  338. package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
  339. package/dist/scripts/frameworks/nuxt/routes.js +54 -0
  340. package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
  341. package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
  342. package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
  343. package/dist/scripts/frameworks/remix/routes.js +50 -0
  344. package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
  345. package/dist/scripts/frameworks/sveltekit/routes.js +50 -0
  346. package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
  347. package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
  348. package/dist/scripts/frameworks/vite/routes.d.ts +15 -0
  349. package/dist/scripts/frameworks/vite/routes.js +93 -0
  350. package/dist/scripts/frameworks/vite/routes.test.d.ts +1 -0
  351. package/dist/scripts/frameworks/vite/routes.test.js +73 -0
  352. package/dist/scripts/frameworks/vite/wiring.d.ts +10 -0
  353. package/dist/scripts/frameworks/vite/wiring.js +99 -0
  354. package/dist/scripts/frameworks/vite/wiring.test.d.ts +1 -0
  355. package/dist/scripts/frameworks/vite/wiring.test.js +88 -0
  356. package/dist/scripts/generated-types.test.d.ts +1 -0
  357. package/dist/scripts/generated-types.test.js +212 -0
  358. package/dist/scripts/lib/validation-report.d.ts +1 -0
  359. package/dist/scripts/lib/validation-report.js +3 -0
  360. package/dist/scripts/lint-translation-keys.test.d.ts +1 -0
  361. package/dist/scripts/lint-translation-keys.test.js +16 -0
  362. package/dist/scripts/render-parity/capture.d.ts +56 -0
  363. package/dist/scripts/render-parity/capture.js +366 -0
  364. package/dist/scripts/render-parity/capture.test.d.ts +1 -0
  365. package/dist/scripts/render-parity/capture.test.js +306 -0
  366. package/dist/scripts/render-parity/compare.d.ts +59 -0
  367. package/dist/scripts/render-parity/compare.js +0 -0
  368. package/dist/scripts/render-parity/compare.test.d.ts +1 -0
  369. package/dist/scripts/render-parity/compare.test.js +98 -0
  370. package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
  371. package/dist/scripts/render-parity/normalize-html.js +223 -0
  372. package/dist/scripts/render-parity/normalize-html.test.d.ts +1 -0
  373. package/dist/scripts/render-parity/normalize-html.test.js +58 -0
  374. package/dist/scripts/render-parity/types.d.ts +41 -0
  375. package/dist/scripts/render-parity/types.js +1 -0
  376. package/dist/scripts/resolve-routes.js +1 -1
  377. package/dist/scripts/scan-wrappable.d.ts +196 -0
  378. package/dist/scripts/scan-wrappable.js +1221 -0
  379. package/dist/scripts/scan-wrappable.test.d.ts +1 -0
  380. package/dist/scripts/scan-wrappable.test.js +502 -0
  381. package/dist/scripts/sync-schemas.test.d.ts +1 -0
  382. package/dist/scripts/sync-schemas.test.js +124 -0
  383. package/dist/scripts/validate-route-metadata.js +11 -0
  384. package/dist/scripts/validate-route-metadata.test.d.ts +1 -0
  385. package/dist/scripts/validate-route-metadata.test.js +116 -0
  386. package/dist/scripts/validate-schemas.test.d.ts +1 -0
  387. package/dist/scripts/validate-schemas.test.js +263 -0
  388. package/package.json +89 -20
  389. package/scripts/add-ext.mjs +47 -0
  390. package/scripts/bump-version.mjs +58 -0
  391. package/scripts/bundle-cli.mjs +123 -0
  392. package/scripts/install-cli.mjs +36 -0
  393. package/scripts/lib/channels.mjs +70 -0
  394. package/scripts/lib/dev-release-state.mjs +44 -0
  395. package/scripts/lib/dev-release-state.test.ts +36 -0
  396. package/scripts/lib/postinstall-onboarding.test.ts +82 -0
  397. package/scripts/lib/release-core.mjs +225 -0
  398. package/scripts/lib/release-core.test.ts +147 -0
  399. package/scripts/migration-qa-gate.test.ts +155 -0
  400. package/scripts/publish-npm.mjs +180 -0
  401. package/templates/react-router/package.json +7 -10
  402. package/templates/react-router/src/pages/Index.tsx +1 -1
  403. package/dist/runtime/content/client/createContentClient.d.ts +0 -5
  404. package/dist/runtime/content/client/createContentClient.js +0 -300
  405. package/dist/runtime/content/client/createSingletonClient.d.ts +0 -5
  406. package/dist/runtime/content/client/createSingletonClient.js +0 -108
  407. package/dist/runtime/content/client/internal.d.ts +0 -44
  408. package/dist/runtime/content/client/internal.js +0 -236
  409. package/dist/runtime/content/client/types.d.ts +0 -136
  410. package/dist/runtime/content/client/useQueryLocale.d.ts +0 -2
  411. package/dist/runtime/content/client/useQueryLocale.js +0 -6
  412. /package/dist/{runtime/content/client/types.js → scripts/apply-wrap-templates.test.d.ts} +0 -0
@@ -0,0 +1,171 @@
1
+ import { join } from 'node:path';
2
+ import { discoverAstroRoutes } from './astro/routes.js';
3
+ import { astroTemplateWrapStyle } from './astro/template-style.js';
4
+ import { rewireNextCollectionPages } from './next/rewire.js';
5
+ import { discoverNextPagesRoutes, discoverNextRoutes } from './next/routes.js';
6
+ import { ensureNextLayoutWiring } from './next/wiring.js';
7
+ import { discoverNuxtRoutes } from './nuxt/routes.js';
8
+ import { nuxtTemplateWrapStyle } from './nuxt/template-style.js';
9
+ import { discoverRemixRoutes } from './remix/routes.js';
10
+ import { discoverSvelteKitRoutes } from './sveltekit/routes.js';
11
+ import { svelteTemplateWrapStyle } from './sveltekit/template-style.js';
12
+ import { discoverReactRouterDomRoutes } from './vite/routes.js';
13
+ import { ensureSpaEntryWiring } from './vite/wiring.js';
14
+ /**
15
+ * Route discovery for any detected framework — the single registry generic
16
+ * code calls. Frameworks without a file convention (vue SPA, plain vite)
17
+ * return [] and rely on fimo-config routes.
18
+ */
19
+ export function discoverFrameworkRoutes(cwd, detection) {
20
+ if (detection.framework === 'vite' && detection.react) {
21
+ return discoverReactRouterDomRoutes(cwd);
22
+ }
23
+ switch (detection.framework) {
24
+ case 'next':
25
+ return [
26
+ ...(detection.appDir ? discoverNextRoutes(join(cwd, detection.appDir)) : []),
27
+ ...(detection.pagesDir ? discoverNextPagesRoutes(join(cwd, detection.pagesDir)) : []),
28
+ ];
29
+ case 'remix':
30
+ return detection.pagesDir ? discoverRemixRoutes(join(cwd, detection.pagesDir)) : [];
31
+ case 'astro':
32
+ return detection.pagesDir ? discoverAstroRoutes(join(cwd, detection.pagesDir)) : [];
33
+ case 'nuxt':
34
+ return detection.pagesDir ? discoverNuxtRoutes(join(cwd, detection.pagesDir)) : [];
35
+ case 'sveltekit':
36
+ return detection.pagesDir ? discoverSvelteKitRoutes(join(cwd, detection.pagesDir)) : [];
37
+ default:
38
+ return [];
39
+ }
40
+ }
41
+ /**
42
+ * Extra directories the framework keeps page COPY in, outside any source
43
+ * root (data-file scanning). Part of the framework registry so generic
44
+ * scanners never carry framework names.
45
+ */
46
+ export function frameworkDataDirs(framework) {
47
+ switch (framework) {
48
+ case 'nuxt':
49
+ return ['content']; // Nuxt Content convention (.yml/.md page documents)
50
+ default:
51
+ return [];
52
+ }
53
+ }
54
+ /**
55
+ * The wrapper-import module for frameworks whose .jsx/.tsx is guaranteed
56
+ * React — the only ones the --apply JSX codemod may touch. Template
57
+ * frameworks return null: a .tsx island there may be Solid or Preact, and
58
+ * injecting a React wrapper import breaks the build (bento dogfood). Bare
59
+ * Vite qualifies only with the detection's `react` flag (a react dependency
60
+ * pins the JSX runtime); the SPA primitives live in fimo/react and are
61
+ * fallback-safe before the providers are wired.
62
+ */
63
+ export function frameworkJsxWrapperModule(detection) {
64
+ switch (detection.framework) {
65
+ case 'next':
66
+ return 'fimo/next';
67
+ case 'remix':
68
+ return 'fimo/remix';
69
+ case 'vite':
70
+ return detection.react ? 'fimo/react' : null;
71
+ default:
72
+ return null;
73
+ }
74
+ }
75
+ /**
76
+ * The template-wrap style for frameworks whose template files the --apply
77
+ * codemod may touch (plain text nodes only). Vue SPA stays null: without a
78
+ * server data path there is no deterministic t() wiring to inject.
79
+ */
80
+ export function frameworkTemplateWrapStyle(framework) {
81
+ switch (framework) {
82
+ case 'astro':
83
+ return astroTemplateWrapStyle;
84
+ case 'nuxt':
85
+ return nuxtTemplateWrapStyle;
86
+ case 'sveltekit':
87
+ return svelteTemplateWrapStyle;
88
+ default:
89
+ return null;
90
+ }
91
+ }
92
+ /**
93
+ * The one-time root-wiring codemod for frameworks whose providers mount in a
94
+ * single well-known file (Next.js app router: the root layout; Vite React
95
+ * SPA: the entry). Runs during --apply, AFTER the baseline capture — the
96
+ * pre-wrap dev-server boot must not require the fimo package, and providers
97
+ * are render-transparent so the parity check stays clean. Template
98
+ * frameworks wire through their TemplateWrapStyle.ensureWiring hooks instead.
99
+ */
100
+ export function frameworkRootWiring(detection) {
101
+ switch (detection.framework) {
102
+ case 'next':
103
+ return (cwd) => ensureNextLayoutWiring(cwd, detection);
104
+ case 'vite':
105
+ return detection.react ? ensureSpaEntryWiring : null;
106
+ default:
107
+ return null;
108
+ }
109
+ }
110
+ /**
111
+ * Collection-page rewiring: pages that render a machine-staged collection get
112
+ * their data source switched to `wrapCollection` (Fimo overlay over the
113
+ * retained source rows) mechanically, with per-page bail reasons. Runs during
114
+ * --apply after drafts are staged; adopt-drafts renames the call-site uids.
115
+ * Next.js app router only for now.
116
+ */
117
+ export function frameworkCollectionRewire(detection) {
118
+ switch (detection.framework) {
119
+ case 'next':
120
+ return (cwd, scan, drafts) => rewireNextCollectionPages(cwd, detection, scan, drafts);
121
+ default:
122
+ return null;
123
+ }
124
+ }
125
+ /**
126
+ * How `wrap --check` proves the root wiring exists: without providers the
127
+ * wrapped values render fallbacks forever, and neither coverage (counts
128
+ * wraps), parity (fallbacks render identically), nor seeding (DB-side)
129
+ * notices — editability would ship silently broken.
130
+ */
131
+ export function frameworkWiringMarker(detection) {
132
+ switch (detection.framework) {
133
+ case 'next':
134
+ if (!detection.appDir) {
135
+ return {
136
+ files: ['pages/_app.tsx', 'pages/_app.jsx', 'src/pages/_app.tsx', 'src/pages/_app.jsx'],
137
+ marker: /FimoNextProviders/,
138
+ hint: 'mount FimoNextProviders in pages/_app (pages router has no automated recipe yet)',
139
+ warnOnly: true,
140
+ };
141
+ }
142
+ return {
143
+ files: [`${detection.appDir}/layout.tsx`, `${detection.appDir}/layout.jsx`, `${detection.appDir}/layout.js`],
144
+ marker: /FimoNextProviders/,
145
+ hint: `mount FimoNextProviders + FimoNextScripts in ${detection.appDir}/layout (agent prompt section 0)`,
146
+ };
147
+ case 'vite':
148
+ if (!detection.react) {
149
+ return null;
150
+ }
151
+ return {
152
+ files: ['src/main.tsx', 'src/main.jsx', 'src/index.tsx', 'src/index.jsx'],
153
+ marker: /FimoSpaProviders/,
154
+ hint: 'wrap the root render with FimoSpaProviders from fimo/react (agent prompt section 0)',
155
+ };
156
+ case 'remix':
157
+ return {
158
+ files: ['app/root.tsx', 'app/root.jsx'],
159
+ marker: /FimoRemixProviders/,
160
+ hint: 'mount FimoRemixProviders in app/root (agent prompt section 0)',
161
+ };
162
+ case 'sveltekit':
163
+ return {
164
+ files: ['src/routes/+layout.server.js', 'src/routes/+layout.server.ts'],
165
+ marker: /fimoLabels/,
166
+ hint: 'return fimoLabels from the root +layout.server load (wrap.md SvelteKit notes)',
167
+ };
168
+ default:
169
+ return null;
170
+ }
171
+ }
@@ -0,0 +1,30 @@
1
+ import type { FrameworkDetection } from '../../detect-framework.js';
2
+ import type { WrapScanResult } from '../../scan-wrappable.js';
3
+ /**
4
+ * Page rewiring for wrap-migrated collections: make each page that renders a
5
+ * machine-staged collection read from Fimo through `wrapCollection` while
6
+ * KEEPING its source rows as the render fallback. Two safe shapes:
7
+ *
8
+ * - an in-code array literal (`const clients = [...]`) rendered by the
9
+ * page's default-export function → the literal is extracted byte-faithful
10
+ * to `src/data/<name>.json` (it becomes the fallback file) and the
11
+ * component fetches `wrapCollection('<Uid>', clientsSource)`;
12
+ * - a data-file default import (`import posts from '../src/data/posts.json'`)
13
+ * → the import becomes `postsSource` and the component fetches
14
+ * `wrapCollection('<Uid>', postsSource)`.
15
+ *
16
+ * Everything else bails with a reason that flows into the agent prompt.
17
+ * Uids are the PROVISIONAL draft names; `schemas adopt-drafts` rewrites the
18
+ * call sites through its renames.
19
+ */
20
+ export interface CollectionRewireResult {
21
+ changes: string[];
22
+ warnings: string[];
23
+ /** Pages successfully rewired. */
24
+ rewired: number;
25
+ }
26
+ export declare function rewireNextCollectionPages(cwd: string, detection: Pick<FrameworkDetection, 'appDir'>, scan: WrapScanResult, drafts: Array<{
27
+ uid: string;
28
+ sourceName: string;
29
+ source: string;
30
+ }>): CollectionRewireResult;
@@ -0,0 +1,258 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parseSync } from 'oxc-parser';
4
+ import { ensureFimoImport } from '../../apply-wrap.js';
5
+ function applyEdits(code, edits) {
6
+ let next = code;
7
+ for (const edit of [...edits].sort((a, b) => b.start - a.start)) {
8
+ next = next.slice(0, edit.start) + edit.replacement + next.slice(edit.end);
9
+ }
10
+ return next;
11
+ }
12
+ function walkAll(node, visit) {
13
+ if (!node || typeof node !== 'object') {
14
+ return;
15
+ }
16
+ if (Array.isArray(node)) {
17
+ for (const child of node) {
18
+ walkAll(child, visit);
19
+ }
20
+ return;
21
+ }
22
+ const record = node;
23
+ if (typeof record.type === 'string') {
24
+ visit(record);
25
+ }
26
+ for (const [key, value] of Object.entries(record)) {
27
+ if (key !== 'type' && value && typeof value === 'object') {
28
+ walkAll(value, visit);
29
+ }
30
+ }
31
+ }
32
+ function defaultExportFunction(program) {
33
+ const exportDefault = (program.body ?? []).find((node) => node.type === 'ExportDefaultDeclaration');
34
+ if (!exportDefault || exportDefault.declaration?.type !== 'FunctionDeclaration') {
35
+ return null;
36
+ }
37
+ const body = exportDefault.declaration.body;
38
+ if (!body || (body.type !== 'FunctionBody' && body.type !== 'BlockStatement')) {
39
+ return null;
40
+ }
41
+ return exportDefault.declaration;
42
+ }
43
+ /** Every reference to `name` (outside `ignoredSpans`) must sit inside the
44
+ * component body — otherwise moving the binding into the component would
45
+ * break module-level consumers (metadata, generateStaticParams, …). */
46
+ function referencesConfinedToFunction(program, name, fn, ignoredSpans) {
47
+ let confined = true;
48
+ walkAll(program, (node) => {
49
+ if (node.type !== 'Identifier' || node.name !== name) {
50
+ return;
51
+ }
52
+ const inIgnored = ignoredSpans.some((span) => node.start >= span.start && node.end <= span.end);
53
+ const inFn = node.start >= fn.body.start && node.end <= fn.body.end;
54
+ if (!inIgnored && !inFn) {
55
+ confined = false;
56
+ }
57
+ });
58
+ return confined;
59
+ }
60
+ function relativeImport(fromFile, toFile) {
61
+ const rel = path.relative(path.dirname(fromFile), toFile).split(path.sep).join('/');
62
+ return rel.startsWith('.') ? rel : `./${rel}`;
63
+ }
64
+ function pageFilesUnder(dir) {
65
+ const out = [];
66
+ const walk = (current) => {
67
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
68
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
69
+ continue;
70
+ }
71
+ const full = path.join(current, entry.name);
72
+ if (entry.isDirectory()) {
73
+ walk(full);
74
+ }
75
+ else if (/\.(tsx|jsx|js)$/.test(entry.name)) {
76
+ out.push(full);
77
+ }
78
+ }
79
+ };
80
+ if (fs.existsSync(dir)) {
81
+ walk(dir);
82
+ }
83
+ return out;
84
+ }
85
+ export function rewireNextCollectionPages(cwd, detection, scan, drafts) {
86
+ const changes = [];
87
+ const warnings = [];
88
+ let rewired = 0;
89
+ if (!detection.appDir) {
90
+ return { changes, warnings: ['Collection pages not rewired: pages-router project.'], rewired };
91
+ }
92
+ const appDirAbs = path.join(cwd, detection.appDir);
93
+ const uidBySourceName = new Map(drafts.map((draft) => [draft.sourceName, draft.uid]));
94
+ const draftsBySourceFile = new Map();
95
+ for (const draft of drafts) {
96
+ const bucket = draftsBySourceFile.get(draft.source) ?? [];
97
+ bucket.push(draft.uid);
98
+ draftsBySourceFile.set(draft.source, bucket);
99
+ }
100
+ const bail = (page, reason) => {
101
+ warnings.push(`Page not rewired (${page}): ${reason} — wire it with wrapCollection per the prompt recipe.`);
102
+ };
103
+ // ── In-code array literals: extract to src/data/<name>.json + wire ──
104
+ for (const candidate of scan.collections) {
105
+ const pageAbs = path.join(cwd, candidate.file);
106
+ if (!pageAbs.startsWith(appDirAbs + path.sep)) {
107
+ bail(candidate.file, `in-code collection \`${candidate.name}\` sits outside the app directory`);
108
+ continue;
109
+ }
110
+ const uid = uidBySourceName.get(candidate.name);
111
+ if (!uid) {
112
+ continue;
113
+ }
114
+ const rows = candidate.typedRows;
115
+ if (!rows || rows.length !== candidate.count) {
116
+ bail(candidate.file, `\`${candidate.name}\` is larger than the extraction window`);
117
+ continue;
118
+ }
119
+ const code = fs.readFileSync(pageAbs, 'utf8');
120
+ if (code.includes("'use client'") || code.includes('"use client"')) {
121
+ bail(candidate.file, 'client component (no server fetch)');
122
+ continue;
123
+ }
124
+ let program;
125
+ try {
126
+ program = parseSync(pageAbs, code).program;
127
+ }
128
+ catch {
129
+ bail(candidate.file, 'could not parse');
130
+ continue;
131
+ }
132
+ // `const x = [...]`, `= [...] as const`, `= [...] satisfies T` all count.
133
+ const isArrayInit = (init) => {
134
+ const inner = init?.type === 'TSAsExpression' || init?.type === 'TSSatisfiesExpression' ? init.expression : init;
135
+ return inner?.type === 'ArrayExpression';
136
+ };
137
+ const declaration = (program.body ?? []).find((node) => node.type === 'VariableDeclaration' &&
138
+ node.declarations?.length === 1 &&
139
+ node.declarations[0]?.id?.name === candidate.name &&
140
+ isArrayInit(node.declarations[0]?.init));
141
+ if (!declaration) {
142
+ bail(candidate.file, `top-level \`const ${candidate.name} = [...]\` not found`);
143
+ continue;
144
+ }
145
+ const fn = defaultExportFunction(program);
146
+ if (!fn) {
147
+ bail(candidate.file, 'the default export is not a plain function declaration');
148
+ continue;
149
+ }
150
+ if (!referencesConfinedToFunction(program, candidate.name, fn, [declaration])) {
151
+ bail(candidate.file, `\`${candidate.name}\` is referenced outside the page component`);
152
+ continue;
153
+ }
154
+ const dataDir = path.join(cwd, 'src', 'data');
155
+ const dataFileAbs = path.join(dataDir, `${candidate.name}.json`);
156
+ if (fs.existsSync(dataFileAbs)) {
157
+ bail(candidate.file, `src/data/${candidate.name}.json already exists`);
158
+ continue;
159
+ }
160
+ fs.mkdirSync(dataDir, { recursive: true });
161
+ fs.writeFileSync(dataFileAbs, `${JSON.stringify(rows, null, 2)}\n`);
162
+ const edits = [{ start: declaration.start, end: declaration.end, replacement: '' }];
163
+ if (!fn.async) {
164
+ edits.push({ start: fn.start, end: fn.start, replacement: 'async ' });
165
+ }
166
+ edits.push({
167
+ start: fn.body.start + 1,
168
+ end: fn.body.start + 1,
169
+ replacement: `\n const ${candidate.name} = await wrapCollection('${uid}', ${candidate.name}Source);\n`,
170
+ });
171
+ let next = applyEdits(code, edits);
172
+ next = `import ${candidate.name}Source from '${relativeImport(pageAbs, dataFileAbs)}';\n${next}`;
173
+ next = ensureFimoImport(next, ['wrapCollection'], 'fimo/next/server');
174
+ fs.writeFileSync(pageAbs, next);
175
+ rewired += 1;
176
+ changes.push(`rewired ${candidate.file}: \`${candidate.name}\` extracted to src/data/${candidate.name}.json and read through wrapCollection('${uid}')`);
177
+ }
178
+ // ── Data-file default imports: wire the importing pages ──
179
+ const dataFileUids = new Map();
180
+ for (const dataFile of scan.dataFiles) {
181
+ const uids = draftsBySourceFile.get(dataFile.file);
182
+ if (uids && uids.length === 1 && /\.json$/i.test(dataFile.file)) {
183
+ dataFileUids.set(path.resolve(cwd, dataFile.file), uids[0]);
184
+ }
185
+ }
186
+ if (dataFileUids.size > 0) {
187
+ for (const pageAbs of pageFilesUnder(appDirAbs)) {
188
+ const code = fs.readFileSync(pageAbs, 'utf8');
189
+ const rel = path.relative(cwd, pageAbs);
190
+ if (!code.includes('src/data/')) {
191
+ continue;
192
+ }
193
+ if (code.includes('wrapCollection(')) {
194
+ continue;
195
+ }
196
+ let program;
197
+ try {
198
+ program = parseSync(pageAbs, code).program;
199
+ }
200
+ catch {
201
+ continue;
202
+ }
203
+ const imports = (program.body ?? []).filter((node) => node.type === 'ImportDeclaration' && typeof node.source?.value === 'string');
204
+ const targets = [];
205
+ for (const declaration of imports) {
206
+ const specifier = (declaration.specifiers ?? []).find((entry) => entry.type === 'ImportDefaultSpecifier');
207
+ if (!specifier || !declaration.source.value.startsWith('.')) {
208
+ continue;
209
+ }
210
+ const resolved = path.resolve(path.dirname(pageAbs), declaration.source.value);
211
+ const uid = dataFileUids.get(resolved);
212
+ if (uid) {
213
+ targets.push({ node: declaration, local: specifier.local.name, uid });
214
+ }
215
+ }
216
+ if (targets.length === 0) {
217
+ continue;
218
+ }
219
+ if (code.includes("'use client'") || code.includes('"use client"')) {
220
+ bail(rel, 'client component (no server fetch)');
221
+ continue;
222
+ }
223
+ const fn = defaultExportFunction(program);
224
+ if (!fn) {
225
+ bail(rel, 'the default export is not a plain function declaration');
226
+ continue;
227
+ }
228
+ const confined = targets.every((target) => referencesConfinedToFunction(program, target.local, fn, [target.node]));
229
+ if (!confined) {
230
+ bail(rel, 'the imported collection is referenced outside the page component');
231
+ continue;
232
+ }
233
+ const edits = [];
234
+ if (!fn.async) {
235
+ edits.push({ start: fn.start, end: fn.start, replacement: 'async ' });
236
+ }
237
+ for (const target of targets) {
238
+ const specifier = (target.node.specifiers ?? []).find((entry) => entry.type === 'ImportDefaultSpecifier');
239
+ edits.push({
240
+ start: specifier.local.start,
241
+ end: specifier.local.end,
242
+ replacement: `${target.local}Source`,
243
+ });
244
+ edits.push({
245
+ start: fn.body.start + 1,
246
+ end: fn.body.start + 1,
247
+ replacement: `\n const ${target.local} = await wrapCollection('${target.uid}', ${target.local}Source);\n`,
248
+ });
249
+ }
250
+ let next = applyEdits(code, edits);
251
+ next = ensureFimoImport(next, ['wrapCollection'], 'fimo/next/server');
252
+ fs.writeFileSync(pageAbs, next);
253
+ rewired += 1;
254
+ changes.push(`rewired ${rel}: ${targets.map((target) => `wrapCollection('${target.uid}')`).join(', ')} over the imported source rows`);
255
+ }
256
+ }
257
+ return { changes, warnings, rewired };
258
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,134 @@
1
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { writeSchemaDrafts } from '../../draft-schemas.js';
6
+ import { scanWrappable } from '../../scan-wrappable.js';
7
+ import { rewireNextCollectionPages } from './rewire.js';
8
+ let dir;
9
+ const project = (files) => {
10
+ dir = mkdtempSync(join(tmpdir(), 'next-rewire-'));
11
+ for (const [rel, content] of Object.entries(files)) {
12
+ const full = join(dir, rel);
13
+ mkdirSync(join(full, '..'), { recursive: true });
14
+ writeFileSync(full, content);
15
+ }
16
+ return dir;
17
+ };
18
+ afterEach(() => {
19
+ if (dir) {
20
+ rmSync(dir, { recursive: true, force: true });
21
+ }
22
+ });
23
+ const run = (root) => {
24
+ const scan = scanWrappable(root, { keepInternal: true });
25
+ const drafts = writeSchemaDrafts(root, scan);
26
+ return rewireNextCollectionPages(root, { appDir: 'app' }, scan, drafts);
27
+ };
28
+ const DATA_PAGE = `import posts from '../../src/data/posts.json';
29
+
30
+ export default function PostsPage() {
31
+ return (
32
+ <main>
33
+ <h1>Posts</h1>
34
+ <ul>
35
+ {posts.slice(0, 24).map((item: any, idx: number) => (
36
+ <li key={idx}><span>{item.title}</span> <span>{item.excerpt}</span></li>
37
+ ))}
38
+ </ul>
39
+ </main>
40
+ );
41
+ }
42
+ `;
43
+ const POSTS_JSON = JSON.stringify([
44
+ { slug: 'post-1', title: 'Charting the bay', excerpt: 'First excerpt of the harbor.' },
45
+ { slug: 'post-2', title: 'Berth songs', excerpt: 'Second excerpt of the crew.' },
46
+ { slug: 'post-3', title: 'Lantern census', excerpt: 'Third excerpt of the reef.' },
47
+ ]);
48
+ const INCODE_PAGE = `const clients = [
49
+ { "name": "Quay anchor Co", "slug": "client-0", "since": "2018-03-20" },
50
+ { "name": "Gull harbor Co", "slug": "client-1", "since": "2015-08-17" },
51
+ { "name": "Crane skiff Co", "slug": "client-2", "since": "2017-07-07" }
52
+ ];
53
+
54
+ export default function ClientsPage() {
55
+ return (
56
+ <main>
57
+ <h1>Clients</h1>
58
+ <ul>
59
+ {clients.map((item, idx) => (
60
+ <li key={idx}><span>{item.name}</span> <span>{item.since}</span></li>
61
+ ))}
62
+ </ul>
63
+ </main>
64
+ );
65
+ }
66
+ `;
67
+ describe('rewireNextCollectionPages', () => {
68
+ it('wires a data-file import page through wrapCollection', () => {
69
+ const root = project({
70
+ 'src/data/posts.json': POSTS_JSON,
71
+ 'app/posts/page.tsx': DATA_PAGE,
72
+ });
73
+ const result = run(root);
74
+ expect(result.rewired).toBe(1);
75
+ const page = readFileSync(join(root, 'app/posts/page.tsx'), 'utf8');
76
+ expect(page).toContain("import postsSource from '../../src/data/posts.json'");
77
+ expect(page).toContain('export default async function PostsPage()');
78
+ expect(page).toContain("const posts = await wrapCollection('Post', postsSource);");
79
+ expect(page).toContain('import { wrapCollection } from "fimo/next/server"');
80
+ });
81
+ it('extracts an in-code array to src/data and wires the page', () => {
82
+ const root = project({
83
+ 'app/clients/page.tsx': INCODE_PAGE,
84
+ });
85
+ const result = run(root);
86
+ expect(result.rewired).toBe(1);
87
+ const extracted = JSON.parse(readFileSync(join(root, 'src/data/clients.json'), 'utf8'));
88
+ expect(extracted).toHaveLength(3);
89
+ expect(extracted[0]).toEqual({ name: 'Quay anchor Co', slug: 'client-0', since: '2018-03-20' });
90
+ const page = readFileSync(join(root, 'app/clients/page.tsx'), 'utf8');
91
+ expect(page).toContain("import clientsSource from '../../src/data/clients.json'");
92
+ expect(page).toContain('export default async function ClientsPage()');
93
+ expect(page).toContain("const clients = await wrapCollection('Client', clientsSource);");
94
+ expect(page).not.toContain('"Quay anchor Co"');
95
+ });
96
+ it('extracts an `as const` in-code array (the generator/create-next-app shape)', () => {
97
+ const root = project({
98
+ 'app/clients/page.tsx': INCODE_PAGE.replace('\n];', '\n] as const;'),
99
+ });
100
+ const result = run(root);
101
+ expect(result.rewired).toBe(1);
102
+ const page = readFileSync(join(root, 'app/clients/page.tsx'), 'utf8');
103
+ expect(page).toContain("const clients = await wrapCollection('Client', clientsSource);");
104
+ expect(page).not.toContain('as const');
105
+ });
106
+ it('bails on client components with a reason', () => {
107
+ const root = project({
108
+ 'src/data/posts.json': POSTS_JSON,
109
+ 'app/posts/page.tsx': `'use client';\n${DATA_PAGE}`,
110
+ });
111
+ const result = run(root);
112
+ expect(result.rewired).toBe(0);
113
+ expect(result.warnings.some((warning) => warning.includes('client component'))).toBe(true);
114
+ });
115
+ it('bails when the collection is referenced outside the page component', () => {
116
+ const root = project({
117
+ 'app/clients/page.tsx': `${INCODE_PAGE}\nexport const clientCount = clients.length;\n`,
118
+ });
119
+ const result = run(root);
120
+ expect(result.rewired).toBe(0);
121
+ expect(result.warnings.some((warning) => warning.includes('referenced outside'))).toBe(true);
122
+ });
123
+ it('is idempotent: an already-wired page is left untouched', () => {
124
+ const root = project({
125
+ 'src/data/posts.json': POSTS_JSON,
126
+ 'app/posts/page.tsx': DATA_PAGE,
127
+ });
128
+ run(root);
129
+ const once = readFileSync(join(root, 'app/posts/page.tsx'), 'utf8');
130
+ const again = run(root);
131
+ expect(readFileSync(join(root, 'app/posts/page.tsx'), 'utf8')).toBe(once);
132
+ expect(again.warnings.filter((warning) => warning.includes('app/posts'))).toHaveLength(0);
133
+ });
134
+ });
@@ -0,0 +1,17 @@
1
+ export interface DiscoveredRoute {
2
+ id: string;
3
+ path: string;
4
+ label: string;
5
+ }
6
+ /**
7
+ * Discover page routes of a Next.js app-router directory (`app/` or
8
+ * `src/app/`). Returns display routes for `fimo-config.json#routes` so the
9
+ * Studio page switcher can enumerate a wrapped site's pages.
10
+ */
11
+ export declare function discoverNextRoutes(appDir: string): DiscoveredRoute[];
12
+ /**
13
+ * Pages-router discovery (`pages/` or `src/pages/`): every module is a route
14
+ * except `_app`/`_document`/`_error` and `api/`. `[param]` segments map to
15
+ * `:param` (the parity capture skips dynamic routes, same as app router).
16
+ */
17
+ export declare function discoverNextPagesRoutes(pagesDir: string): DiscoveredRoute[];