fimo 0.7.0-experimental.2 → 0.7.0-experimental.4
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.
- package/README.md +1 -1
- package/assets/content-templates/hooks-template.eta +27 -73
- package/assets/content-templates/types-template.eta +1 -4
- package/assets/skills/fimo/SKILL.md +2 -2
- package/assets/skills/fimo/references/content.md +42 -46
- package/assets/skills/fimo/references/locales.md +0 -8
- package/assets/skills/fimo/references/setup-react-router.md +2 -2
- package/assets/skills/fimo/references/ui.md +1 -1
- package/assets/skills/fimo-cli/references/content.md +14 -17
- package/assets/skills/fimo-cli/references/domains.md +1 -1
- package/assets/skills/fimo-cli/references/locales.md +0 -6
- package/assets/skills/fimo-migration/SKILL.md +22 -2
- package/assets/skills/fimo-migration/references/content.md +8 -0
- package/assets/skills/fimo-migration/references/manifest.md +35 -0
- package/assets/skills/fimo-migration/references/qa.md +24 -2
- package/assets/skills/fimo-migration/references/workflow.md +12 -1
- package/assets/skills/fimo-migration/references/wrap.md +582 -0
- package/assets/skills/fimo-studio/references/custom-domains.md +1 -1
- package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
- package/dist/build/vite/index.d.ts.map +1 -0
- package/dist/build/vite/plugins/content-sync.d.ts.map +1 -0
- package/dist/build/vite/plugins/content-sync.test.d.ts +2 -0
- package/dist/build/vite/plugins/content-sync.test.d.ts.map +1 -0
- package/dist/build/vite/plugins/content-sync.test.js +64 -0
- package/dist/build/vite/plugins/data-id.d.ts.map +1 -0
- package/dist/build/vite/plugins/fimo-config.d.ts.map +1 -0
- package/dist/build/vite/plugins/fimo-config.test.d.ts +2 -0
- package/dist/build/vite/plugins/fimo-config.test.d.ts.map +1 -0
- package/dist/build/vite/plugins/fimo-config.test.js +46 -0
- package/dist/build/vite/plugins/overlay.d.ts.map +1 -0
- package/dist/build/vite/plugins/robots.d.ts.map +1 -0
- package/dist/build/vite/plugins/seo.d.ts.map +1 -0
- package/dist/build/vite/plugins/server-config.d.ts.map +1 -0
- package/dist/build/vite/plugins/sitemap.d.ts.map +1 -0
- package/dist/build/vite/plugins/translations.d.ts +2 -8
- package/dist/build/vite/plugins/translations.d.ts.map +1 -0
- package/dist/build/vite/plugins/translations.js +3 -121
- package/dist/build/vite/plugins/translations.test.d.ts +2 -0
- package/dist/build/vite/plugins/translations.test.d.ts.map +1 -0
- package/dist/build/vite/plugins/translations.test.js +266 -0
- package/dist/cli/bundle.json +2 -3
- package/dist/cli/index.js +117939 -1186
- package/dist/runtime/app/FimoProviders.d.ts +1 -11
- package/dist/runtime/app/FimoProviders.d.ts.map +1 -0
- package/dist/runtime/app/FimoProviders.js +2 -23
- package/dist/runtime/app/FimoScripts.d.ts.map +1 -0
- package/dist/runtime/app/index.d.ts.map +1 -0
- package/dist/runtime/app/prefetch.d.ts.map +1 -0
- package/dist/runtime/astro/index.d.ts +2 -0
- package/dist/runtime/astro/index.d.ts.map +1 -0
- package/dist/runtime/astro/index.js +3 -0
- package/dist/runtime/astro/server.d.ts +3 -0
- package/dist/runtime/astro/server.d.ts.map +1 -0
- package/dist/runtime/astro/server.js +6 -0
- package/dist/runtime/content/DataSourcesProvider.d.ts.map +1 -0
- package/dist/runtime/content/RefreshContentProvider.d.ts.map +1 -0
- package/dist/runtime/content/RefreshContentProvider.test.d.ts +2 -0
- package/dist/runtime/content/RefreshContentProvider.test.d.ts.map +1 -0
- package/dist/runtime/content/RefreshContentProvider.test.js +33 -0
- package/dist/runtime/content/parseCollectionResponse.d.ts.map +1 -0
- package/dist/runtime/content/parseCollectionResponse.test.d.ts +2 -0
- package/dist/runtime/content/parseCollectionResponse.test.d.ts.map +1 -0
- package/dist/runtime/content/parseCollectionResponse.test.js +20 -0
- package/dist/runtime/content/utils/retrieve-data-sources.d.ts +0 -1
- package/dist/runtime/content/utils/retrieve-data-sources.d.ts.map +1 -0
- package/dist/runtime/content/utils/retrieve-data-sources.js +4 -27
- package/dist/runtime/core/AppErrorBoundary.d.ts.map +1 -0
- package/dist/runtime/core/ViteLifecycles.d.ts.map +1 -0
- package/dist/runtime/i18n/FimoLocaleContext.d.ts.map +1 -0
- package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
- package/dist/runtime/i18n/locale.d.ts.map +1 -0
- package/dist/runtime/i18n/locale.test.d.ts +2 -0
- package/dist/runtime/i18n/locale.test.d.ts.map +1 -0
- package/dist/runtime/i18n/locale.test.js +58 -0
- package/dist/runtime/iframe/ConsoleErrorProvider.d.ts.map +1 -0
- package/dist/runtime/iframe/ScreenshotProvider.d.ts.map +1 -0
- package/dist/runtime/iframe/runtime/overlay-hmr.d.ts.map +1 -0
- package/dist/runtime/iframe/runtime/overlay-hmr.js +0 -3
- package/dist/runtime/iframe/runtime/overlay-runtime.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +0 -3
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +0 -2
- package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
- package/dist/runtime/next/FimoNextProviders.d.ts.map +1 -0
- package/dist/runtime/next/FimoNextProviders.js +20 -0
- package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
- package/dist/runtime/next/FimoNextScripts.d.ts.map +1 -0
- package/dist/runtime/next/FimoNextScripts.js +19 -0
- package/dist/runtime/next/index.d.ts +14 -0
- package/dist/runtime/next/index.d.ts.map +1 -0
- package/dist/runtime/next/index.js +14 -0
- package/dist/runtime/next/server.d.ts +2 -0
- package/dist/runtime/next/server.d.ts.map +1 -0
- package/dist/runtime/next/server.js +4 -0
- package/dist/runtime/nuxt/composables.d.ts +9 -0
- package/dist/runtime/nuxt/composables.d.ts.map +1 -0
- package/dist/runtime/nuxt/composables.js +57 -0
- package/dist/runtime/nuxt/index.d.ts +3 -0
- package/dist/runtime/nuxt/index.d.ts.map +1 -0
- package/dist/runtime/nuxt/index.js +6 -0
- package/dist/runtime/nuxt/server.d.ts +3 -0
- package/dist/runtime/nuxt/server.d.ts.map +1 -0
- package/dist/runtime/nuxt/server.js +6 -0
- package/dist/runtime/paths/get-fimo-paths.d.ts.map +1 -0
- package/dist/runtime/paths/get-fimo-paths.js +5 -15
- package/dist/runtime/paths/index.d.ts.map +1 -0
- package/dist/runtime/paths/types.d.ts.map +1 -0
- package/dist/runtime/primitives/components/Boolean.d.ts.map +1 -0
- package/dist/runtime/primitives/components/Date.d.ts.map +1 -0
- package/dist/runtime/primitives/components/Image.d.ts.map +1 -0
- package/dist/runtime/primitives/components/RichText.d.ts.map +1 -0
- package/dist/runtime/primitives/components/StaticImage.d.ts.map +1 -0
- package/dist/runtime/primitives/components/Text.d.ts.map +1 -0
- package/dist/runtime/primitives/components/Video.d.ts.map +1 -0
- package/dist/runtime/primitives/components/index.d.ts.map +1 -0
- package/dist/runtime/primitives/index.d.ts.map +1 -0
- package/dist/runtime/primitives/labels-hook.d.ts +33 -0
- package/dist/runtime/primitives/labels-hook.d.ts.map +1 -0
- package/dist/runtime/primitives/labels-hook.js +41 -0
- package/dist/runtime/primitives/labels-store.d.ts +12 -0
- package/dist/runtime/primitives/labels-store.d.ts.map +1 -0
- package/dist/runtime/primitives/labels-store.js +60 -0
- package/dist/runtime/primitives/labels-store.test.d.ts +2 -0
- package/dist/runtime/primitives/labels-store.test.d.ts.map +1 -0
- package/dist/runtime/primitives/labels-store.test.js +66 -0
- package/dist/runtime/primitives/lib/image-optimization.d.ts.map +1 -0
- package/dist/runtime/primitives/lib/index.d.ts.map +1 -0
- package/dist/runtime/primitives/lib/primitives.d.ts +2 -2
- package/dist/runtime/primitives/lib/primitives.d.ts.map +1 -0
- package/dist/runtime/primitives/lib/query.d.ts +3 -5
- package/dist/runtime/primitives/lib/query.d.ts.map +1 -0
- package/dist/runtime/primitives/lib/template.d.ts.map +1 -0
- package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
- package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts.map +1 -0
- package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
- package/dist/runtime/primitives/public-surface.test.d.ts +2 -0
- package/dist/runtime/primitives/public-surface.test.d.ts.map +1 -0
- package/dist/runtime/primitives/public-surface.test.js +45 -0
- package/dist/runtime/primitives/translations.d.ts +1 -27
- package/dist/runtime/primitives/translations.d.ts.map +1 -0
- package/dist/runtime/primitives/translations.js +7 -85
- package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
- package/dist/runtime/react/FimoSpaProviders.d.ts.map +1 -0
- package/dist/runtime/react/FimoSpaProviders.js +63 -0
- package/dist/runtime/react/index.d.ts +33 -0
- package/dist/runtime/react/index.d.ts.map +1 -0
- package/dist/runtime/react/index.js +39 -0
- package/dist/runtime/react-router/index.d.ts.map +1 -0
- package/dist/runtime/react-router/navigation-utils.d.ts.map +1 -0
- package/dist/runtime/react-router/navigation.d.ts.map +1 -0
- package/dist/runtime/react-router/navigation.test.d.ts +2 -0
- package/dist/runtime/react-router/navigation.test.d.ts.map +1 -0
- package/dist/runtime/react-router/navigation.test.js +35 -0
- package/dist/runtime/react-router/routes.d.ts.map +1 -0
- package/dist/runtime/react-router/routes.test.d.ts +2 -0
- package/dist/runtime/react-router/routes.test.d.ts.map +1 -0
- package/dist/runtime/react-router/routes.test.js +67 -0
- package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
- package/dist/runtime/remix/FimoRemixProviders.d.ts.map +1 -0
- package/dist/runtime/remix/FimoRemixProviders.js +12 -0
- package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
- package/dist/runtime/remix/FimoRemixScripts.d.ts.map +1 -0
- package/dist/runtime/remix/FimoRemixScripts.js +19 -0
- package/dist/runtime/remix/index.d.ts +12 -0
- package/dist/runtime/remix/index.d.ts.map +1 -0
- package/dist/runtime/remix/index.js +11 -0
- package/dist/runtime/remix/server.d.ts +2 -0
- package/dist/runtime/remix/server.d.ts.map +1 -0
- package/dist/runtime/remix/server.js +2 -0
- package/dist/runtime/routing/AppResetScrollOnNavigate.d.ts.map +1 -0
- package/dist/runtime/routing/AppRoutesProvider.d.ts.map +1 -0
- package/dist/runtime/seo/buildSeoForPath.d.ts +3 -1
- package/dist/runtime/seo/buildSeoForPath.d.ts.map +1 -0
- package/dist/runtime/seo/buildSeoForPath.js +1 -4
- package/dist/runtime/seo/htmlProps.d.ts.map +1 -0
- package/dist/runtime/seo/index.d.ts.map +1 -0
- package/dist/runtime/seo/resolver.d.ts.map +1 -0
- package/dist/runtime/shared/display-routes.d.ts +14 -0
- package/dist/runtime/shared/display-routes.d.ts.map +1 -0
- package/dist/runtime/shared/display-routes.js +25 -0
- package/dist/runtime/shared/fimo-config.server.d.ts.map +1 -0
- package/dist/runtime/shared/fimo-config.server.js +1 -0
- package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
- package/dist/runtime/shared/fimo-config.types.d.ts.map +1 -0
- package/dist/runtime/shared/i18n-messages.d.ts +29 -0
- package/dist/runtime/shared/i18n-messages.d.ts.map +1 -0
- package/dist/runtime/shared/i18n-messages.js +79 -0
- package/dist/runtime/shared/i18n-messages.test.d.ts +2 -0
- package/dist/runtime/shared/i18n-messages.test.d.ts.map +1 -0
- package/dist/runtime/shared/i18n-messages.test.js +39 -0
- package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
- package/dist/runtime/shared/labels-fetch.pure.d.ts.map +1 -0
- package/dist/runtime/shared/labels-fetch.pure.js +71 -0
- package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
- package/dist/runtime/shared/labels-fetch.server.d.ts.map +1 -0
- package/dist/runtime/shared/labels-fetch.server.js +97 -0
- package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
- package/dist/runtime/shared/labels-t.pure.d.ts.map +1 -0
- package/dist/runtime/shared/labels-t.pure.js +10 -0
- package/dist/runtime/svelte/index.d.ts +3 -0
- package/dist/runtime/svelte/index.d.ts.map +1 -0
- package/dist/runtime/svelte/index.js +7 -0
- package/dist/runtime/svelte/server.d.ts +3 -0
- package/dist/runtime/svelte/server.d.ts.map +1 -0
- package/dist/runtime/svelte/server.js +6 -0
- package/dist/runtime/t/OptionalTracking.d.ts.map +1 -0
- package/dist/runtime/t/OptionalTracking.test.d.ts +2 -0
- package/dist/runtime/t/OptionalTracking.test.d.ts.map +1 -0
- package/dist/runtime/t/OptionalTracking.test.js +11 -0
- package/dist/runtime/t/Pageview.d.ts.map +1 -0
- package/dist/runtime/templates.d.ts.map +1 -0
- package/dist/runtime/vue/index.d.ts +3 -0
- package/dist/runtime/vue/index.d.ts.map +1 -0
- package/dist/runtime/vue/index.js +5 -0
- package/dist/runtime/vue/server.d.ts +3 -0
- package/dist/runtime/vue/server.d.ts.map +1 -0
- package/dist/runtime/vue/server.js +6 -0
- package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
- package/dist/runtime/wrapped/FimoFileLink.d.ts.map +1 -0
- package/dist/runtime/wrapped/FimoFileLink.js +19 -0
- package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
- package/dist/runtime/wrapped/FimoMediaImage.d.ts.map +1 -0
- package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
- package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
- package/dist/runtime/wrapped/FimoMediaVideo.d.ts.map +1 -0
- package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +23 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.d.ts.map +1 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
- package/dist/runtime/wrapped/FimoText.d.ts +22 -0
- package/dist/runtime/wrapped/FimoText.d.ts.map +1 -0
- package/dist/runtime/wrapped/FimoText.js +20 -0
- package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
- package/dist/runtime/wrapped/WrappedContentContext.d.ts.map +1 -0
- package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
- package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
- package/dist/runtime/wrapped/WrappedProviders.d.ts.map +1 -0
- package/dist/runtime/wrapped/WrappedProviders.js +101 -0
- package/dist/runtime/wrapped/dom.d.ts +4 -0
- package/dist/runtime/wrapped/dom.d.ts.map +1 -0
- package/dist/runtime/wrapped/dom.js +23 -0
- package/dist/runtime/wrapped/dom.test.d.ts +2 -0
- package/dist/runtime/wrapped/dom.test.d.ts.map +1 -0
- package/dist/runtime/wrapped/dom.test.js +16 -0
- package/dist/runtime/wrapped/server.d.ts +77 -0
- package/dist/runtime/wrapped/server.d.ts.map +1 -0
- package/dist/runtime/wrapped/server.js +237 -0
- package/dist/runtime/wrapped/server.test.d.ts +2 -0
- package/dist/runtime/wrapped/server.test.d.ts.map +1 -0
- package/dist/runtime/wrapped/server.test.js +91 -0
- package/dist/scripts/apply-wrap-templates.d.ts +61 -0
- package/dist/scripts/apply-wrap-templates.js +132 -0
- package/dist/scripts/apply-wrap-templates.test.js +199 -0
- package/dist/scripts/apply-wrap.d.ts +46 -0
- package/dist/scripts/apply-wrap.js +278 -0
- package/dist/scripts/apply-wrap.test.d.ts +1 -0
- package/dist/scripts/apply-wrap.test.js +226 -0
- package/dist/scripts/cms/discover.d.ts +2 -0
- package/dist/scripts/cms/discover.js +17 -0
- package/dist/scripts/cms/example-content.d.ts +32 -0
- package/dist/scripts/cms/example-content.js +87 -0
- package/dist/scripts/cms/example-content.test.d.ts +1 -0
- package/dist/scripts/cms/example-content.test.js +57 -0
- package/dist/scripts/cms/strapi/detect.d.ts +2 -0
- package/dist/scripts/cms/strapi/detect.js +185 -0
- package/dist/scripts/cms/strapi/detect.test.d.ts +1 -0
- package/dist/scripts/cms/strapi/detect.test.js +56 -0
- package/dist/scripts/cms/strapi/index.d.ts +3 -0
- package/dist/scripts/cms/strapi/index.js +15 -0
- package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
- package/dist/scripts/cms/strapi/list-source.js +90 -0
- package/dist/scripts/cms/strapi/list-source.test.d.ts +1 -0
- package/dist/scripts/cms/strapi/list-source.test.js +33 -0
- package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
- package/dist/scripts/cms/strapi/schema-map.js +138 -0
- package/dist/scripts/cms/strapi/schema-map.test.d.ts +1 -0
- package/dist/scripts/cms/strapi/schema-map.test.js +87 -0
- package/dist/scripts/cms/types.d.ts +76 -0
- package/dist/scripts/cms/types.js +11 -0
- package/dist/scripts/detect-framework.d.ts +39 -0
- package/dist/scripts/detect-framework.js +133 -0
- package/dist/scripts/detect-framework.test.d.ts +1 -0
- package/dist/scripts/detect-framework.test.js +122 -0
- package/dist/scripts/draft-rows.d.ts +19 -0
- package/dist/scripts/draft-rows.js +135 -0
- package/dist/scripts/draft-rows.test.d.ts +1 -0
- package/dist/scripts/draft-rows.test.js +113 -0
- package/dist/scripts/draft-schemas.d.ts +27 -0
- package/dist/scripts/draft-schemas.js +188 -0
- package/dist/scripts/draft-schemas.test.d.ts +1 -0
- package/dist/scripts/draft-schemas.test.js +152 -0
- package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
- package/dist/scripts/frameworks/astro/routes.js +55 -0
- package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
- package/dist/scripts/frameworks/astro/template-style.js +19 -0
- package/dist/scripts/frameworks/discover.d.ts +70 -0
- package/dist/scripts/frameworks/discover.js +171 -0
- package/dist/scripts/frameworks/next/rewire.d.ts +30 -0
- package/dist/scripts/frameworks/next/rewire.js +258 -0
- package/dist/scripts/frameworks/next/rewire.test.d.ts +1 -0
- package/dist/scripts/frameworks/next/rewire.test.js +134 -0
- package/dist/scripts/frameworks/next/routes.d.ts +17 -0
- package/dist/scripts/frameworks/next/routes.js +134 -0
- package/dist/scripts/frameworks/next/routes.test.d.ts +1 -0
- package/dist/scripts/frameworks/next/routes.test.js +64 -0
- package/dist/scripts/frameworks/next/wiring.d.ts +26 -0
- package/dist/scripts/frameworks/next/wiring.js +163 -0
- package/dist/scripts/frameworks/next/wiring.test.d.ts +1 -0
- package/dist/scripts/frameworks/next/wiring.test.js +146 -0
- package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
- package/dist/scripts/frameworks/nuxt/routes.js +54 -0
- package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
- package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
- package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
- package/dist/scripts/frameworks/remix/routes.js +50 -0
- package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
- package/dist/scripts/frameworks/sveltekit/routes.js +50 -0
- package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
- package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
- package/dist/scripts/frameworks/vite/routes.d.ts +15 -0
- package/dist/scripts/frameworks/vite/routes.js +93 -0
- package/dist/scripts/frameworks/vite/routes.test.d.ts +1 -0
- package/dist/scripts/frameworks/vite/routes.test.js +73 -0
- package/dist/scripts/frameworks/vite/wiring.d.ts +10 -0
- package/dist/scripts/frameworks/vite/wiring.js +99 -0
- package/dist/scripts/frameworks/vite/wiring.test.d.ts +1 -0
- package/dist/scripts/frameworks/vite/wiring.test.js +88 -0
- package/dist/scripts/generated-types.test.d.ts +1 -0
- package/dist/scripts/generated-types.test.js +212 -0
- package/dist/scripts/lib/validation-report.d.ts +1 -0
- package/dist/scripts/lib/validation-report.js +3 -0
- package/dist/scripts/lint-translation-keys.test.d.ts +1 -0
- package/dist/scripts/lint-translation-keys.test.js +16 -0
- package/dist/scripts/render-parity/capture.d.ts +56 -0
- package/dist/scripts/render-parity/capture.js +366 -0
- package/dist/scripts/render-parity/capture.test.d.ts +1 -0
- package/dist/scripts/render-parity/capture.test.js +306 -0
- package/dist/scripts/render-parity/compare.d.ts +59 -0
- package/dist/scripts/render-parity/compare.js +0 -0
- package/dist/scripts/render-parity/compare.test.d.ts +1 -0
- package/dist/scripts/render-parity/compare.test.js +98 -0
- package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
- package/dist/scripts/render-parity/normalize-html.js +223 -0
- package/dist/scripts/render-parity/normalize-html.test.d.ts +1 -0
- package/dist/scripts/render-parity/normalize-html.test.js +58 -0
- package/dist/scripts/render-parity/types.d.ts +41 -0
- package/dist/scripts/render-parity/types.js +1 -0
- package/dist/scripts/resolve-routes.js +1 -1
- package/dist/scripts/scan-wrappable.d.ts +196 -0
- package/dist/scripts/scan-wrappable.js +1221 -0
- package/dist/scripts/scan-wrappable.test.d.ts +1 -0
- package/dist/scripts/scan-wrappable.test.js +502 -0
- package/dist/scripts/sync-schemas.test.d.ts +1 -0
- package/dist/scripts/sync-schemas.test.js +124 -0
- package/dist/scripts/validate-route-metadata.js +11 -0
- package/dist/scripts/validate-route-metadata.test.d.ts +1 -0
- package/dist/scripts/validate-route-metadata.test.js +116 -0
- package/dist/scripts/validate-schemas.test.d.ts +1 -0
- package/dist/scripts/validate-schemas.test.js +263 -0
- package/package.json +85 -20
- package/scripts/add-ext.mjs +47 -0
- package/scripts/bump-version.mjs +58 -0
- package/scripts/bundle-cli.mjs +123 -0
- package/scripts/install-cli.mjs +36 -0
- package/scripts/lib/channels.mjs +70 -0
- package/scripts/lib/dev-release-state.mjs +44 -0
- package/scripts/lib/dev-release-state.test.ts +36 -0
- package/scripts/lib/postinstall-onboarding.test.ts +82 -0
- package/scripts/lib/release-core.mjs +225 -0
- package/scripts/lib/release-core.test.ts +147 -0
- package/scripts/migration-qa-gate.test.ts +155 -0
- package/scripts/publish-npm.mjs +180 -0
- package/templates/react-router/package.json +7 -10
- package/templates/react-router/src/pages/Index.tsx +1 -1
- package/dist/runtime/content/client/createContentClient.d.ts +0 -5
- package/dist/runtime/content/client/createContentClient.js +0 -300
- package/dist/runtime/content/client/createSingletonClient.d.ts +0 -5
- package/dist/runtime/content/client/createSingletonClient.js +0 -108
- package/dist/runtime/content/client/internal.d.ts +0 -44
- package/dist/runtime/content/client/internal.js +0 -236
- package/dist/runtime/content/client/types.d.ts +0 -136
- package/dist/runtime/content/client/useQueryLocale.d.ts +0 -2
- package/dist/runtime/content/client/useQueryLocale.js +0 -6
- /package/dist/{runtime/content/client/types.js → scripts/apply-wrap-templates.test.d.ts} +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
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
|
+
/**
|
|
6
|
+
* Next.js-side wrap wiring: everything the wrap migration must touch that is
|
|
7
|
+
* specific to this framework lives HERE, not in the generic flow. Mirror this
|
|
8
|
+
* module when adding a framework (see the fimo-framework-adapter skill).
|
|
9
|
+
*/
|
|
10
|
+
export function ensureNextWiring(cwd) {
|
|
11
|
+
const changes = [];
|
|
12
|
+
const warnings = [];
|
|
13
|
+
const configFile = ['next.config.ts', 'next.config.mjs', 'next.config.js', 'next.config.cjs']
|
|
14
|
+
.map((candidate) => path.join(cwd, candidate))
|
|
15
|
+
.find((candidate) => fs.existsSync(candidate));
|
|
16
|
+
if (configFile) {
|
|
17
|
+
const source = fs.readFileSync(configFile, 'utf8');
|
|
18
|
+
if (!source.includes('allowedDevOrigins')) {
|
|
19
|
+
// The three mainstream config shapes: a named object binding, a direct
|
|
20
|
+
// `export default {` literal, and CJS `module.exports = {`.
|
|
21
|
+
let patched = source.replace(/(const\s+nextConfig[^=]*=\s*\{)/, `$1\n allowedDevOrigins: ['*.preview.fimo.ai'],`);
|
|
22
|
+
if (patched === source) {
|
|
23
|
+
patched = source.replace(/((?:export\s+default|module\.exports\s*=)\s*\{)/, `$1\n allowedDevOrigins: ['*.preview.fimo.ai'],\n`);
|
|
24
|
+
}
|
|
25
|
+
if (patched !== source) {
|
|
26
|
+
fs.writeFileSync(configFile, patched);
|
|
27
|
+
changes.push(`added allowedDevOrigins to ${path.basename(configFile)}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
warnings.push(`Could not patch ${path.basename(configFile)} automatically — add: allowedDevOrigins: ['*.preview.fimo.ai']`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
warnings.push("No next.config found — create one with: allowedDevOrigins: ['*.preview.fimo.ai']");
|
|
36
|
+
}
|
|
37
|
+
return { changes, warnings };
|
|
38
|
+
}
|
|
39
|
+
function findFirst(node, predicate) {
|
|
40
|
+
if (!node || typeof node !== 'object') {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if (predicate(node)) {
|
|
44
|
+
return node;
|
|
45
|
+
}
|
|
46
|
+
for (const value of Object.values(node)) {
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
for (const entry of value) {
|
|
49
|
+
const found = findFirst(entry, predicate);
|
|
50
|
+
if (found) {
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (value && typeof value === 'object') {
|
|
56
|
+
const found = findFirst(value, predicate);
|
|
57
|
+
if (found) {
|
|
58
|
+
return found;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const jsxName = (element) => element?.openingElement?.name?.name;
|
|
65
|
+
/**
|
|
66
|
+
* Wire the app-router root layout deterministically: imports, async default
|
|
67
|
+
* export, loader calls, `<FimoNextScripts />` in head, and `{children}`
|
|
68
|
+
* wrapped in `<FimoNextProviders>`. Only the provably safe shape is touched —
|
|
69
|
+
* one default-exported function whose JSX returns `<html>…<body>` with a
|
|
70
|
+
* `{children}` expression somewhere inside body (create-next-app and its
|
|
71
|
+
* variants). Anything else bails with the reason, and the agent prompt keeps
|
|
72
|
+
* the manual recipe.
|
|
73
|
+
*/
|
|
74
|
+
export function ensureNextLayoutWiring(cwd, detection) {
|
|
75
|
+
if (!detection.appDir) {
|
|
76
|
+
return {
|
|
77
|
+
changes: [],
|
|
78
|
+
warnings: ['Root wiring not applied: pages-router project (no app directory) — wire pages/_app manually.'],
|
|
79
|
+
wired: false,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const layoutFile = ['layout.tsx', 'layout.jsx', 'layout.js']
|
|
83
|
+
.map((candidate) => path.join(cwd, detection.appDir, candidate))
|
|
84
|
+
.find((candidate) => fs.existsSync(candidate));
|
|
85
|
+
const rel = layoutFile ? path.relative(cwd, layoutFile) : `${detection.appDir}/layout.tsx`;
|
|
86
|
+
const bail = (reason) => ({
|
|
87
|
+
changes: [],
|
|
88
|
+
warnings: [`Root wiring not applied: ${reason} — follow the layout recipe in the agent prompt (${rel}).`],
|
|
89
|
+
wired: false,
|
|
90
|
+
});
|
|
91
|
+
if (!layoutFile) {
|
|
92
|
+
return bail('no root layout file found');
|
|
93
|
+
}
|
|
94
|
+
const code = fs.readFileSync(layoutFile, 'utf8');
|
|
95
|
+
if (code.includes('FimoNextProviders')) {
|
|
96
|
+
return { changes: [], warnings: [], wired: true };
|
|
97
|
+
}
|
|
98
|
+
let program;
|
|
99
|
+
try {
|
|
100
|
+
program = parseSync(layoutFile, code).program;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return bail('root layout could not be parsed');
|
|
104
|
+
}
|
|
105
|
+
const exportDefault = (program.body ?? []).find((node) => node.type === 'ExportDefaultDeclaration');
|
|
106
|
+
if (!exportDefault || exportDefault.declaration?.type !== 'FunctionDeclaration') {
|
|
107
|
+
return bail('the default export is not a plain function declaration');
|
|
108
|
+
}
|
|
109
|
+
const layoutFn = exportDefault.declaration;
|
|
110
|
+
const body = layoutFn.body;
|
|
111
|
+
if (!body || (body.type !== 'FunctionBody' && body.type !== 'BlockStatement')) {
|
|
112
|
+
return bail('the layout function has no block body');
|
|
113
|
+
}
|
|
114
|
+
const html = findFirst(body, (node) => node?.type === 'JSXElement' && jsxName(node) === 'html');
|
|
115
|
+
if (!html) {
|
|
116
|
+
return bail('the layout does not return an <html> element');
|
|
117
|
+
}
|
|
118
|
+
const htmlBody = (html.children ?? []).find((child) => child?.type === 'JSXElement' && jsxName(child) === 'body');
|
|
119
|
+
if (!htmlBody) {
|
|
120
|
+
return bail('no <body> element found under <html>');
|
|
121
|
+
}
|
|
122
|
+
const childrenExpr = findFirst(htmlBody, (node) => node?.type === 'JSXExpressionContainer' &&
|
|
123
|
+
node.expression?.type === 'Identifier' &&
|
|
124
|
+
node.expression?.name === 'children');
|
|
125
|
+
if (!childrenExpr) {
|
|
126
|
+
return bail('no {children} expression found inside <body>');
|
|
127
|
+
}
|
|
128
|
+
const edits = [];
|
|
129
|
+
if (!layoutFn.async) {
|
|
130
|
+
edits.push({ start: layoutFn.start, end: layoutFn.start, replacement: 'async ' });
|
|
131
|
+
}
|
|
132
|
+
edits.push({
|
|
133
|
+
start: body.start + 1,
|
|
134
|
+
end: body.start + 1,
|
|
135
|
+
replacement: '\n const config = loadFimoConfig();\n const labels = await loadFimoLabels();\n',
|
|
136
|
+
});
|
|
137
|
+
edits.push({
|
|
138
|
+
start: childrenExpr.start,
|
|
139
|
+
end: childrenExpr.end,
|
|
140
|
+
replacement: `<FimoNextProviders config={config} labels={labels}>${code.slice(childrenExpr.start, childrenExpr.end)}</FimoNextProviders>`,
|
|
141
|
+
});
|
|
142
|
+
const head = (html.children ?? []).find((child) => child?.type === 'JSXElement' && jsxName(child) === 'head');
|
|
143
|
+
if (head) {
|
|
144
|
+
const at = head.openingElement.end;
|
|
145
|
+
edits.push({ start: at, end: at, replacement: '<FimoNextScripts />' });
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
const at = html.openingElement.end;
|
|
149
|
+
edits.push({
|
|
150
|
+
start: at,
|
|
151
|
+
end: at,
|
|
152
|
+
replacement: '\n <head>\n <FimoNextScripts />\n </head>',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
let next = code;
|
|
156
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
157
|
+
next = next.slice(0, edit.start) + edit.replacement + next.slice(edit.end);
|
|
158
|
+
}
|
|
159
|
+
next = ensureFimoImport(next, ['FimoNextProviders', 'FimoNextScripts'], 'fimo/next');
|
|
160
|
+
next = ensureFimoImport(next, ['loadFimoConfig', 'loadFimoLabels'], 'fimo/next/server');
|
|
161
|
+
fs.writeFileSync(layoutFile, next);
|
|
162
|
+
return { changes: [`wired Fimo providers into ${rel}`], warnings: [], wired: true };
|
|
163
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
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 { ensureNextLayoutWiring, ensureNextWiring } from './wiring.js';
|
|
6
|
+
let dir;
|
|
7
|
+
const project = (files) => {
|
|
8
|
+
dir = mkdtempSync(join(tmpdir(), 'next-wiring-'));
|
|
9
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
10
|
+
const full = join(dir, rel);
|
|
11
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
12
|
+
writeFileSync(full, content);
|
|
13
|
+
}
|
|
14
|
+
return dir;
|
|
15
|
+
};
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
if (dir) {
|
|
18
|
+
rmSync(dir, { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const CREATE_NEXT_APP_LAYOUT = `import type { Metadata } from 'next';
|
|
22
|
+
import './globals.css';
|
|
23
|
+
|
|
24
|
+
export const metadata: Metadata = { title: 'Harbor Docs' };
|
|
25
|
+
|
|
26
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
27
|
+
return (
|
|
28
|
+
<html lang="en">
|
|
29
|
+
<body className="antialiased">{children}</body>
|
|
30
|
+
</html>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
describe('ensureNextLayoutWiring', () => {
|
|
35
|
+
it('wires the create-next-app default layout end to end', () => {
|
|
36
|
+
const root = project({ 'app/layout.tsx': CREATE_NEXT_APP_LAYOUT });
|
|
37
|
+
const result = ensureNextLayoutWiring(root, { appDir: 'app' });
|
|
38
|
+
const code = readFileSync(join(root, 'app/layout.tsx'), 'utf8');
|
|
39
|
+
expect(result.wired).toBe(true);
|
|
40
|
+
expect(result.changes).toEqual(['wired Fimo providers into app/layout.tsx']);
|
|
41
|
+
expect(code).toContain('import { FimoNextProviders, FimoNextScripts } from "fimo/next";');
|
|
42
|
+
expect(code).toContain('import { loadFimoConfig, loadFimoLabels } from "fimo/next/server";');
|
|
43
|
+
expect(code).toContain('export default async function RootLayout');
|
|
44
|
+
expect(code).toContain('const config = loadFimoConfig();');
|
|
45
|
+
expect(code).toContain('const labels = await loadFimoLabels();');
|
|
46
|
+
expect(code).toContain('<body className="antialiased"><FimoNextProviders config={config} labels={labels}>{children}</FimoNextProviders></body>');
|
|
47
|
+
expect(code).toContain('<head>');
|
|
48
|
+
expect(code).toContain('<FimoNextScripts />');
|
|
49
|
+
// Head lands inside <html>, before <body>.
|
|
50
|
+
expect(code.indexOf('<FimoNextScripts />')).toBeGreaterThan(code.indexOf('<html'));
|
|
51
|
+
expect(code.indexOf('<FimoNextScripts />')).toBeLessThan(code.indexOf('<body'));
|
|
52
|
+
});
|
|
53
|
+
it('reuses an existing <head> element and keeps an async layout async', () => {
|
|
54
|
+
const root = project({
|
|
55
|
+
'src/app/layout.jsx': `export default async function Layout({ children }) {
|
|
56
|
+
return (
|
|
57
|
+
<html>
|
|
58
|
+
<head>
|
|
59
|
+
<link rel="icon" href="/favicon.ico" />
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<div id="shell">{children}</div>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
`,
|
|
68
|
+
});
|
|
69
|
+
const result = ensureNextLayoutWiring(root, { appDir: 'src/app' });
|
|
70
|
+
const code = readFileSync(join(root, 'src/app/layout.jsx'), 'utf8');
|
|
71
|
+
expect(result.wired).toBe(true);
|
|
72
|
+
expect(code).not.toContain('async async');
|
|
73
|
+
expect(code).toContain('<head><FimoNextScripts />');
|
|
74
|
+
// children was NOT a direct body child — the nested container still wraps.
|
|
75
|
+
expect(code).toContain('<FimoNextProviders config={config} labels={labels}>{children}</FimoNextProviders>');
|
|
76
|
+
expect(code.match(/<head>/g)).toHaveLength(1);
|
|
77
|
+
});
|
|
78
|
+
it('is a no-op when the layout is already wired', () => {
|
|
79
|
+
const wired = CREATE_NEXT_APP_LAYOUT.replace('{children}', '<FimoNextProviders>{children}</FimoNextProviders>');
|
|
80
|
+
const root = project({ 'app/layout.tsx': wired });
|
|
81
|
+
const result = ensureNextLayoutWiring(root, { appDir: 'app' });
|
|
82
|
+
expect(result.wired).toBe(true);
|
|
83
|
+
expect(result.changes).toEqual([]);
|
|
84
|
+
expect(readFileSync(join(root, 'app/layout.tsx'), 'utf8')).toBe(wired);
|
|
85
|
+
});
|
|
86
|
+
it('bails on pages-router-only projects', () => {
|
|
87
|
+
const root = project({ 'pages/index.tsx': 'export default function Home() { return <p>hi</p>; }\n' });
|
|
88
|
+
const result = ensureNextLayoutWiring(root, { appDir: undefined });
|
|
89
|
+
expect(result.wired).toBe(false);
|
|
90
|
+
expect(result.warnings[0]).toContain('pages-router');
|
|
91
|
+
});
|
|
92
|
+
it('bails when the default export is not a plain function', () => {
|
|
93
|
+
const source = `const Layout = ({ children }) => <html><body>{children}</body></html>;
|
|
94
|
+
export default Layout;
|
|
95
|
+
`;
|
|
96
|
+
const root = project({ 'app/layout.tsx': source });
|
|
97
|
+
const result = ensureNextLayoutWiring(root, { appDir: 'app' });
|
|
98
|
+
expect(result.wired).toBe(false);
|
|
99
|
+
expect(result.warnings[0]).toContain('not a plain function declaration');
|
|
100
|
+
expect(readFileSync(join(root, 'app/layout.tsx'), 'utf8')).toBe(source);
|
|
101
|
+
});
|
|
102
|
+
it('bails when no {children} expression exists inside <body>', () => {
|
|
103
|
+
const root = project({
|
|
104
|
+
'app/layout.tsx': `export default function Layout(props) {
|
|
105
|
+
return (
|
|
106
|
+
<html>
|
|
107
|
+
<body>{props.children}</body>
|
|
108
|
+
</html>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
`,
|
|
112
|
+
});
|
|
113
|
+
const result = ensureNextLayoutWiring(root, { appDir: 'app' });
|
|
114
|
+
expect(result.wired).toBe(false);
|
|
115
|
+
expect(result.warnings[0]).toContain('no {children} expression');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe('ensureNextWiring config patch', () => {
|
|
119
|
+
it('patches the named nextConfig binding', () => {
|
|
120
|
+
const root = project({
|
|
121
|
+
'next.config.ts': `const nextConfig = {\n reactStrictMode: true,\n};\nexport default nextConfig;\n`,
|
|
122
|
+
});
|
|
123
|
+
const result = ensureNextWiring(root);
|
|
124
|
+
expect(result.changes).toEqual(['added allowedDevOrigins to next.config.ts']);
|
|
125
|
+
expect(readFileSync(join(root, 'next.config.ts'), 'utf8')).toContain("allowedDevOrigins: ['*.preview.fimo.ai'],");
|
|
126
|
+
});
|
|
127
|
+
it('patches a direct export default object literal (.mjs)', () => {
|
|
128
|
+
const root = project({
|
|
129
|
+
'next.config.mjs': `/** @type {import('next').NextConfig} */\nexport default {};\n`,
|
|
130
|
+
});
|
|
131
|
+
const result = ensureNextWiring(root);
|
|
132
|
+
expect(result.changes).toEqual(['added allowedDevOrigins to next.config.mjs']);
|
|
133
|
+
const code = readFileSync(join(root, 'next.config.mjs'), 'utf8');
|
|
134
|
+
expect(code).toContain("allowedDevOrigins: ['*.preview.fimo.ai'],");
|
|
135
|
+
expect(code).toContain('export default {');
|
|
136
|
+
});
|
|
137
|
+
it('patches module.exports form and warns on unrecognized shapes', () => {
|
|
138
|
+
const cjs = project({ 'next.config.cjs': `module.exports = {\n poweredByHeader: false,\n};\n` });
|
|
139
|
+
expect(ensureNextWiring(cjs).changes).toHaveLength(1);
|
|
140
|
+
rmSync(cjs, { recursive: true, force: true });
|
|
141
|
+
const weird = project({ 'next.config.js': `module.exports = buildConfig();\n` });
|
|
142
|
+
const result = ensureNextWiring(weird);
|
|
143
|
+
expect(result.changes).toEqual([]);
|
|
144
|
+
expect(result.warnings[0]).toContain('Could not patch next.config.js');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const titleCase = (seg) => seg
|
|
4
|
+
.replace(/[_\-]+/g, ' ')
|
|
5
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
6
|
+
.split(/\s+/)
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
9
|
+
.join(' ');
|
|
10
|
+
function pushRoute(routes, parts) {
|
|
11
|
+
const routePath = `/${parts.join('/')}`.replace(/\/+/g, '/');
|
|
12
|
+
const lastStatic = [...parts].reverse().find((part) => !part.startsWith(':'));
|
|
13
|
+
routes.push({
|
|
14
|
+
id: routePath === '/' ? 'home' : parts.map((part) => part.replace(/^:/, '')).join('-'),
|
|
15
|
+
path: routePath,
|
|
16
|
+
label: routePath === '/' ? 'Home' : titleCase(lastStatic ?? parts[parts.length - 1] ?? routePath),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const toSegment = (name) => name.replace(/^\[\.\.\.(.+)\]$/, ':$1').replace(/^\[(.+)\]$/, ':$1');
|
|
20
|
+
/** Nuxt file-based routes under pages/ (index.vue maps to the dir path). */
|
|
21
|
+
export function discoverNuxtRoutes(pagesDir) {
|
|
22
|
+
const routes = [];
|
|
23
|
+
const walk = (dir, segments) => {
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = readdirSync(dir);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const full = join(dir, entry);
|
|
33
|
+
let isDir = false;
|
|
34
|
+
try {
|
|
35
|
+
isDir = statSync(full).isDirectory();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (isDir) {
|
|
41
|
+
walk(full, [...segments, toSegment(entry)]);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (!entry.endsWith('.vue')) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const base = entry.replace(/\.vue$/, '');
|
|
48
|
+
pushRoute(routes, base === 'index' ? segments : [...segments, toSegment(base)]);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
walk(pagesDir, []);
|
|
52
|
+
routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
53
|
+
return routes;
|
|
54
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TemplateWrapStyle } from '../../apply-wrap-templates.js';
|
|
2
|
+
/**
|
|
3
|
+
* Nuxt template wraps: the useFimoT composable is client-safe (fimo/nuxt
|
|
4
|
+
* never pulls server loaders into the bundle) and transfers the dictionary
|
|
5
|
+
* through the Nuxt payload, so a single `<script setup>` line wires a file.
|
|
6
|
+
* Options-API scripts have no safe injection point (top-level await needs
|
|
7
|
+
* setup) — those files stay agent work.
|
|
8
|
+
*/
|
|
9
|
+
export declare const nuxtTemplateWrapStyle: TemplateWrapStyle;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt template wraps: the useFimoT composable is client-safe (fimo/nuxt
|
|
3
|
+
* never pulls server loaders into the bundle) and transfers the dictionary
|
|
4
|
+
* through the Nuxt payload, so a single `<script setup>` line wires a file.
|
|
5
|
+
* Options-API scripts have no safe injection point (top-level await needs
|
|
6
|
+
* setup) — those files stay agent work.
|
|
7
|
+
*/
|
|
8
|
+
export const nuxtTemplateWrapStyle = {
|
|
9
|
+
ext: '.vue',
|
|
10
|
+
head: "import { useFimoT } from 'fimo/nuxt'\nconst t = await useFimoT()",
|
|
11
|
+
headMarker: /useFimoT/,
|
|
12
|
+
open: '{{ t(',
|
|
13
|
+
close: ') }}',
|
|
14
|
+
injectHead: (code, head) => {
|
|
15
|
+
// An SFC may carry BOTH <script> and <script setup>: target the setup
|
|
16
|
+
// block specifically (top-level await is only legal there).
|
|
17
|
+
const setup = code.match(/<script[^>]*\bsetup\b[^>]*>\r?\n?/);
|
|
18
|
+
if (setup && setup.index !== undefined) {
|
|
19
|
+
const at = setup.index + setup[0].length;
|
|
20
|
+
return `${code.slice(0, at)}${head}\n${code.slice(at)}`;
|
|
21
|
+
}
|
|
22
|
+
if (/<script\b/.test(code)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return `<script setup>\n${head}\n</script>\n\n${code}`;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs';
|
|
2
|
+
const titleCase = (seg) => seg
|
|
3
|
+
.replace(/[_\-]+/g, ' ')
|
|
4
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
5
|
+
.split(/\s+/)
|
|
6
|
+
.filter(Boolean)
|
|
7
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
8
|
+
.join(' ');
|
|
9
|
+
function pushRoute(routes, parts) {
|
|
10
|
+
const routePath = `/${parts.join('/')}`.replace(/\/+/g, '/');
|
|
11
|
+
const lastStatic = [...parts].reverse().find((part) => !part.startsWith(':'));
|
|
12
|
+
routes.push({
|
|
13
|
+
id: routePath === '/' ? 'home' : parts.map((part) => part.replace(/^:/, '')).join('-'),
|
|
14
|
+
path: routePath,
|
|
15
|
+
label: routePath === '/' ? 'Home' : titleCase(lastStatic ?? parts[parts.length - 1] ?? routePath),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const FILE_EXT = /\.(tsx|jsx|ts|js|mdx)$/;
|
|
19
|
+
/** Remix v2 flat routes under app/routes: dots are slashes, $param is dynamic. */
|
|
20
|
+
export function discoverRemixRoutes(routesDir) {
|
|
21
|
+
const routes = [];
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = readdirSync(routesDir);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return routes;
|
|
28
|
+
}
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (!FILE_EXT.test(entry)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const base = entry.replace(FILE_EXT, '');
|
|
34
|
+
if (base === '_index') {
|
|
35
|
+
pushRoute(routes, []);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// Pathless layout segments start with _ ; trailing ._index maps to the parent.
|
|
39
|
+
const parts = base
|
|
40
|
+
.replace(/\._index$/, '')
|
|
41
|
+
.split('.')
|
|
42
|
+
.filter((seg) => !seg.startsWith('_'))
|
|
43
|
+
.map((seg) => (seg.startsWith('$') ? `:${seg.slice(1) || 'splat'}` : seg));
|
|
44
|
+
if (parts.length > 0) {
|
|
45
|
+
pushRoute(routes, parts);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
49
|
+
return routes;
|
|
50
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const titleCase = (seg) => seg
|
|
4
|
+
.replace(/[_\-]+/g, ' ')
|
|
5
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
6
|
+
.split(/\s+/)
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
9
|
+
.join(' ');
|
|
10
|
+
function pushRoute(routes, parts) {
|
|
11
|
+
const routePath = `/${parts.join('/')}`.replace(/\/+/g, '/');
|
|
12
|
+
const lastStatic = [...parts].reverse().find((part) => !part.startsWith(':'));
|
|
13
|
+
routes.push({
|
|
14
|
+
id: routePath === '/' ? 'home' : parts.map((part) => part.replace(/^:/, '')).join('-'),
|
|
15
|
+
path: routePath,
|
|
16
|
+
label: routePath === '/' ? 'Home' : titleCase(lastStatic ?? parts[parts.length - 1] ?? routePath),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const toSegment = (name) => name.replace(/^\[\.\.\.(.+)\]$/, ':$1').replace(/^\[(.+)\]$/, ':$1');
|
|
20
|
+
/** SvelteKit routes: every directory under src/routes holding a +page file. */
|
|
21
|
+
export function discoverSvelteKitRoutes(routesDir) {
|
|
22
|
+
const routes = [];
|
|
23
|
+
const walk = (dir, segments) => {
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = readdirSync(dir);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (entries.some((entry) => /^\+page\.(svelte|md)$/.test(entry))) {
|
|
32
|
+
// Route groups (parens) are layout-only segments.
|
|
33
|
+
pushRoute(routes, segments.filter((seg) => !seg.startsWith('(')));
|
|
34
|
+
}
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
const full = join(dir, entry);
|
|
37
|
+
try {
|
|
38
|
+
if (statSync(full).isDirectory()) {
|
|
39
|
+
walk(full, [...segments, toSegment(entry)]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
walk(routesDir, []);
|
|
48
|
+
routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
49
|
+
return routes;
|
|
50
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type TemplateWrapStyle } from '../../apply-wrap-templates.js';
|
|
2
|
+
/**
|
|
3
|
+
* SvelteKit template wraps. The t binding is deliberately a mode-agnostic
|
|
4
|
+
* `const` — a `$derived` flips a legacy component into runes mode (breaking
|
|
5
|
+
* its own `$:` statements) and a `$:` reactive runs after init (arrays built
|
|
6
|
+
* at init see undefined). Labels only change with a reload in edit mode,
|
|
7
|
+
* which the wrap contract accepts.
|
|
8
|
+
*/
|
|
9
|
+
export declare const svelteTemplateWrapStyle: TemplateWrapStyle;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join } from 'node:path';
|
|
3
|
+
import { injectIntoInstanceScript } from '../../apply-wrap-templates.js';
|
|
4
|
+
import { slugify } from '../../apply-wrap.js';
|
|
5
|
+
/**
|
|
6
|
+
* SvelteKit template wraps. The t binding is deliberately a mode-agnostic
|
|
7
|
+
* `const` — a `$derived` flips a legacy component into runes mode (breaking
|
|
8
|
+
* its own `$:` statements) and a `$:` reactive runs after init (arrays built
|
|
9
|
+
* at init see undefined). Labels only change with a reload in edit mode,
|
|
10
|
+
* which the wrap contract accepts.
|
|
11
|
+
*/
|
|
12
|
+
export const svelteTemplateWrapStyle = {
|
|
13
|
+
ext: '.svelte',
|
|
14
|
+
head: "import { page } from '$app/stores';\n\timport { makeFimoT } from 'fimo/svelte';\n\tconst t = makeFimoT($page.data.fimoLabels);",
|
|
15
|
+
headMarker: /makeFimoT/,
|
|
16
|
+
open: '{t(',
|
|
17
|
+
close: ')}',
|
|
18
|
+
injectHead: (code, head) => injectIntoInstanceScript(code, head, '<script>'),
|
|
19
|
+
// Route-convention filenames carry no meaning: scope +page/+layout keys by
|
|
20
|
+
// their route directory (src/routes/pricing/+page.svelte -> "pricing").
|
|
21
|
+
fileScope: (file) => {
|
|
22
|
+
const stem = basename(file).replace(/\.svelte$/, '');
|
|
23
|
+
if (!stem.startsWith('+')) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const dir = basename(dirname(file));
|
|
27
|
+
if (!dir || dir === 'routes' || dir === 'src') {
|
|
28
|
+
return stem === '+layout' ? 'layout' : 'home';
|
|
29
|
+
}
|
|
30
|
+
return slugify(dir) || 'home';
|
|
31
|
+
},
|
|
32
|
+
// The store form reads $page.data.fimoLabels: wire the root server load
|
|
33
|
+
// once when the project has none. An existing +layout.server.* is agent
|
|
34
|
+
// work (merging into a user load function is judgment, and until then the
|
|
35
|
+
// inline fallbacks keep rendering identical).
|
|
36
|
+
ensureWiring: (rootDir) => {
|
|
37
|
+
const routesDir = join(rootDir, 'src', 'routes');
|
|
38
|
+
const existing = ['+layout.server.js', '+layout.server.ts'].some((name) => existsSync(join(routesDir, name)));
|
|
39
|
+
if (existing || !existsSync(routesDir)) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
const layoutPath = join(routesDir, '+layout.server.js');
|
|
43
|
+
writeFileSync(layoutPath, [
|
|
44
|
+
"import { loadFimoLabels } from 'fimo/svelte/server';",
|
|
45
|
+
'',
|
|
46
|
+
'export const load = async () => {',
|
|
47
|
+
'\tconst labels = await loadFimoLabels();',
|
|
48
|
+
'\treturn { fimoLabels: labels.dictionaries[labels.defaultLocale] ?? {} };',
|
|
49
|
+
'};',
|
|
50
|
+
'',
|
|
51
|
+
].join('\n'));
|
|
52
|
+
return ['src/routes/+layout.server.js'];
|
|
53
|
+
},
|
|
54
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DiscoveredRoute } from '../next/routes.js';
|
|
2
|
+
/**
|
|
3
|
+
* Route discovery for Vite React SPAs: there is no file convention, so the
|
|
4
|
+
* routes live in react-router code. v1 reads LITERAL, ABSOLUTE paths from the
|
|
5
|
+
* two mainstream declaration shapes —
|
|
6
|
+
*
|
|
7
|
+
* <Route path="/pricing" element={…} /> (JSX tree)
|
|
8
|
+
* createBrowserRouter([{ path: '/pricing', … }]) (object form)
|
|
9
|
+
*
|
|
10
|
+
* — in files that import react-router. Relative child paths and index routes
|
|
11
|
+
* need the router's nesting semantics to resolve; they (and `*` wildcards)
|
|
12
|
+
* stay out of v1: the fimo-config route registry accepts manual entries for
|
|
13
|
+
* anything the scan cannot see, and scanned routes only ever ADD to it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function discoverReactRouterDomRoutes(rootDir: string): DiscoveredRoute[];
|