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.
- package/README.md +2 -3
- package/assets/content-templates/hooks-template.eta +27 -73
- package/assets/content-templates/types-template.eta +1 -4
- package/assets/skills/fimo/SKILL.md +3 -3
- package/assets/skills/fimo/references/assets.md +2 -2
- package/assets/skills/fimo/references/content.md +43 -47
- package/assets/skills/fimo/references/design.md +1 -1
- 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/SKILL.md +1 -1
- package/assets/skills/fimo-cli/references/assets.md +24 -7
- package/assets/skills/fimo-cli/references/content.md +16 -19
- package/assets/skills/fimo-cli/references/domains.md +1 -1
- package/assets/skills/fimo-cli/references/locales.md +0 -6
- package/assets/skills/fimo-cli/references/media.md +142 -132
- 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 +118296 -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/strapi/client.d.ts +26 -0
- package/dist/runtime/strapi/client.d.ts.map +1 -0
- package/dist/runtime/strapi/client.js +88 -0
- package/dist/runtime/strapi/client.test.d.ts +2 -0
- package/dist/runtime/strapi/client.test.d.ts.map +1 -0
- package/dist/runtime/strapi/client.test.js +64 -0
- package/dist/runtime/strapi/index.d.ts +5 -0
- package/dist/runtime/strapi/index.d.ts.map +1 -0
- package/dist/runtime/strapi/index.js +6 -0
- package/dist/runtime/strapi/reshape.d.ts +28 -0
- package/dist/runtime/strapi/reshape.d.ts.map +1 -0
- package/dist/runtime/strapi/reshape.js +79 -0
- package/dist/runtime/strapi/reshape.test.d.ts +2 -0
- package/dist/runtime/strapi/reshape.test.d.ts.map +1 -0
- package/dist/runtime/strapi/reshape.test.js +33 -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 +108 -0
- package/dist/scripts/cms/example-content.test.d.ts +1 -0
- package/dist/scripts/cms/example-content.test.js +66 -0
- package/dist/scripts/cms/strapi/detect.d.ts +2 -0
- package/dist/scripts/cms/strapi/detect.js +186 -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 +23 -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 +149 -0
- package/dist/scripts/cms/strapi/schema-map.test.d.ts +1 -0
- package/dist/scripts/cms/strapi/schema-map.test.js +91 -0
- package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
- package/dist/scripts/cms/strapi/wire-client.js +107 -0
- package/dist/scripts/cms/strapi/wire-client.test.d.ts +1 -0
- package/dist/scripts/cms/strapi/wire-client.test.js +51 -0
- package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
- package/dist/scripts/cms/strapi/wiring.js +36 -0
- package/dist/scripts/cms/strapi/wiring.test.d.ts +1 -0
- package/dist/scripts/cms/strapi/wiring.test.js +27 -0
- package/dist/scripts/cms/types.d.ts +94 -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 +89 -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,17 @@
|
|
|
1
|
+
import type { CmsCollectionSchema } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Machine-wiring for the native `fimo/strapi` read adapter. From the scaffolded
|
|
4
|
+
* schemas it derives the Strapi-path → Fimo-type map (+ the singletons) and
|
|
5
|
+
* emits a tiny repo module that instantiates the Fimo-backed fetch. The
|
|
6
|
+
* migration then swaps the CMS client's `fetch` for `fimoStrapiFetch` — after
|
|
7
|
+
* which the whole site reads scaffolded content from Fimo, deterministically.
|
|
8
|
+
*/
|
|
9
|
+
export interface StrapiWiring {
|
|
10
|
+
/** Strapi REST path segment (pluralName) → Fimo type name. */
|
|
11
|
+
types: Record<string, string>;
|
|
12
|
+
/** Fimo type names that are single types. */
|
|
13
|
+
singletons: string[];
|
|
14
|
+
}
|
|
15
|
+
export declare function strapiWiring(schemas: CmsCollectionSchema[]): StrapiWiring;
|
|
16
|
+
/** Emit the repo module (`fimo-strapi.ts`) that wires the fetch to Fimo. */
|
|
17
|
+
export declare function renderFimoStrapiModule(schemas: CmsCollectionSchema[]): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function strapiWiring(schemas) {
|
|
2
|
+
const types = {};
|
|
3
|
+
const singletons = [];
|
|
4
|
+
for (const schema of schemas) {
|
|
5
|
+
const pluralName = schema.sourcePath.replace(/^\/+/, '');
|
|
6
|
+
if (pluralName) {
|
|
7
|
+
types[pluralName] = schema.name;
|
|
8
|
+
}
|
|
9
|
+
if (schema.isSingleton) {
|
|
10
|
+
singletons.push(schema.name);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return { types, singletons };
|
|
14
|
+
}
|
|
15
|
+
/** Emit the repo module (`fimo-strapi.ts`) that wires the fetch to Fimo. */
|
|
16
|
+
export function renderFimoStrapiModule(schemas) {
|
|
17
|
+
const { types, singletons } = strapiWiring(schemas);
|
|
18
|
+
const typeEntries = Object.entries(types)
|
|
19
|
+
.map(([pluralName, typeName]) => ` '${pluralName}': '${typeName}',`)
|
|
20
|
+
.join('\n');
|
|
21
|
+
return `// AUTO-GENERATED by \`fimo migrate --scaffold-cms\`. Serves this site's Strapi
|
|
22
|
+
// content reads from Fimo (scaffolded example content) through fimo/strapi.
|
|
23
|
+
// The migration points the CMS client's fetch at \`fimoStrapiFetch\`; reads for
|
|
24
|
+
// scaffolded types resolve from Fimo, everything else falls through to Strapi.
|
|
25
|
+
import { createFimoStrapiFetch } from 'fimo/strapi';
|
|
26
|
+
|
|
27
|
+
// Strapi REST path (pluralName) -> Fimo type name.
|
|
28
|
+
const TYPES: Record<string, string> = {
|
|
29
|
+
${typeEntries}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const SINGLETONS = [${singletons.map((name) => `'${name}'`).join(', ')}];
|
|
33
|
+
|
|
34
|
+
export const fimoStrapiFetch = createFimoStrapiFetch({ types: TYPES, singletons: SINGLETONS });
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { renderFimoStrapiModule, strapiWiring } from './wiring.js';
|
|
3
|
+
const schema = (name, sourcePath, isSingleton = false) => ({
|
|
4
|
+
name,
|
|
5
|
+
label: name,
|
|
6
|
+
isSingleton,
|
|
7
|
+
localized: false,
|
|
8
|
+
fields: {},
|
|
9
|
+
sourceUid: `api::${name.toLowerCase()}.${name.toLowerCase()}`,
|
|
10
|
+
sourcePath,
|
|
11
|
+
});
|
|
12
|
+
describe('strapiWiring', () => {
|
|
13
|
+
it('maps pluralName paths to Fimo types and lists singletons', () => {
|
|
14
|
+
const wiring = strapiWiring([schema('BlogPost', '/blog-posts'), schema('Global', '/globals', true)]);
|
|
15
|
+
expect(wiring.types).toEqual({ 'blog-posts': 'BlogPost', globals: 'Global' });
|
|
16
|
+
expect(wiring.singletons).toEqual(['Global']);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe('renderFimoStrapiModule', () => {
|
|
20
|
+
it('emits a module importing fimo/strapi with the type map + singletons', () => {
|
|
21
|
+
const src = renderFimoStrapiModule([schema('BlogPost', '/blog-posts'), schema('Global', '/globals', true)]);
|
|
22
|
+
expect(src).toContain("import { createFimoStrapiFetch } from 'fimo/strapi';");
|
|
23
|
+
expect(src).toContain("'blog-posts': 'BlogPost',");
|
|
24
|
+
expect(src).toContain("const SINGLETONS = ['Global'];");
|
|
25
|
+
expect(src).toContain('export const fimoStrapiFetch = createFimoStrapiFetch({ types: TYPES, singletons: SINGLETONS });');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CMS-connector contract. A connector recognizes an external headless CMS
|
|
3
|
+
* behind a wrapped frontend and reads its content-type definitions into the
|
|
4
|
+
* neutral Fimo schema shape — WITHOUT connecting to the CMS at runtime.
|
|
5
|
+
*
|
|
6
|
+
* The connector seam mirrors the framework-adapter contract: a CMS's name and
|
|
7
|
+
* quirks live ONLY under `scripts/cms/<cms>/`. Everything above (the registry,
|
|
8
|
+
* the example-content generator, the orchestrator wiring) is CMS-neutral. A
|
|
9
|
+
* CMS name appearing in neutral code is a review finding.
|
|
10
|
+
*/
|
|
11
|
+
/** Scalar Fimo field types (see `FieldTypeSchema` in api-contracts). */
|
|
12
|
+
export type FimoScalarType = 'string' | 'richtext' | 'media' | 'number' | 'boolean' | 'date' | 'json';
|
|
13
|
+
export interface FimoScalarField {
|
|
14
|
+
readonly type: FimoScalarType;
|
|
15
|
+
}
|
|
16
|
+
export interface FimoReferenceField {
|
|
17
|
+
readonly type: 'reference';
|
|
18
|
+
/** Single-target reference (Fimo type name). */
|
|
19
|
+
readonly target?: string;
|
|
20
|
+
/** Poly-target reference (Fimo type names). */
|
|
21
|
+
readonly targets?: string[];
|
|
22
|
+
/** True for to-many relations. */
|
|
23
|
+
readonly many?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export type FimoFieldDef = FimoScalarField | FimoReferenceField;
|
|
26
|
+
/**
|
|
27
|
+
* One CMS content type mapped to the Fimo schema shape. `fields` is the exact
|
|
28
|
+
* pushable `contentType.fields` payload; `name`/`label`/`isSingleton` complete
|
|
29
|
+
* the `api.createSchema` call.
|
|
30
|
+
*/
|
|
31
|
+
export interface CmsCollectionSchema {
|
|
32
|
+
/** Fimo type name (PascalCase — deterministic from the CMS singular name). */
|
|
33
|
+
readonly name: string;
|
|
34
|
+
/** Human display label. */
|
|
35
|
+
readonly label: string;
|
|
36
|
+
/** Strapi singleType → true; collectionType → false. */
|
|
37
|
+
readonly isSingleton: boolean;
|
|
38
|
+
/** The CMS marks this type as localized → seed per configured locale. */
|
|
39
|
+
readonly localized: boolean;
|
|
40
|
+
readonly fields: Record<string, FimoFieldDef>;
|
|
41
|
+
/** Pre-computed example values for fields the generic generator can't shape
|
|
42
|
+
* from the Fimo field type alone (dynamic zones must be arrays, components
|
|
43
|
+
* objects). Keyed by field name; the generator uses these verbatim. */
|
|
44
|
+
readonly examples?: Record<string, unknown>;
|
|
45
|
+
/** Source CMS uid for provenance (e.g. `api::blog-post.blog-post`). */
|
|
46
|
+
readonly sourceUid: string;
|
|
47
|
+
/** Source REST path (e.g. `/blog-posts`) — informational for later rewire. */
|
|
48
|
+
readonly sourcePath: string;
|
|
49
|
+
}
|
|
50
|
+
/** What a connector reports about a detected CMS. */
|
|
51
|
+
export interface CmsDetection {
|
|
52
|
+
/** Connector name, capitalized for the data-source prompt (e.g. `Strapi`). */
|
|
53
|
+
readonly cms: string;
|
|
54
|
+
/** Host label recorded in the data-source decision. */
|
|
55
|
+
readonly host: string;
|
|
56
|
+
/** Absolute path to the CMS app root when co-located (monorepo), else null. */
|
|
57
|
+
readonly appDir: string | null;
|
|
58
|
+
/** Absolute path to the frontend's CMS client module dir (where the fetch
|
|
59
|
+
* lives), for machine-wiring the reads to Fimo. Null if not found. */
|
|
60
|
+
readonly clientDir: string | null;
|
|
61
|
+
/** Repo-relative files/signals that evidenced the detection. */
|
|
62
|
+
readonly evidence: string[];
|
|
63
|
+
/** Locales configured in the CMS, when discoverable (may be empty). */
|
|
64
|
+
readonly locales: string[];
|
|
65
|
+
}
|
|
66
|
+
export interface CmsConnector {
|
|
67
|
+
readonly detection: CmsDetection;
|
|
68
|
+
/**
|
|
69
|
+
* Read every content-type definition into the Fimo schema shape. Returns an
|
|
70
|
+
* empty array when the schemas are not locally available (decoupled CMS with
|
|
71
|
+
* no co-located source) — detection can still surface the source for a
|
|
72
|
+
* keep-live decision even when schema import is impossible.
|
|
73
|
+
*/
|
|
74
|
+
readSchemas(): CmsCollectionSchema[];
|
|
75
|
+
/**
|
|
76
|
+
* Emit a generic list-read helper (as source text) the agent wires into the
|
|
77
|
+
* site's LIST views so they render the scaffolded example content from Fimo.
|
|
78
|
+
* Returns null when the CMS has no such helper. `serverImport` is the
|
|
79
|
+
* framework's Fimo server subpath (e.g. `fimo/next/server`) the helper imports
|
|
80
|
+
* `fetchEntries` from.
|
|
81
|
+
*/
|
|
82
|
+
renderListSource?(schemas: CmsCollectionSchema[], serverImport: string): string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Machine-wire the frontend's CMS reads to Fimo: emit the adapter module and
|
|
85
|
+
* swap the client's fetch, so the whole site reads scaffolded content from
|
|
86
|
+
* Fimo. Deterministic — no agent step.
|
|
87
|
+
*/
|
|
88
|
+
wireClient?(cwd: string, schemas: CmsCollectionSchema[]): CmsWireResult;
|
|
89
|
+
}
|
|
90
|
+
export interface CmsWireResult {
|
|
91
|
+
changes: string[];
|
|
92
|
+
warnings: string[];
|
|
93
|
+
wired: boolean;
|
|
94
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CMS-connector contract. A connector recognizes an external headless CMS
|
|
3
|
+
* behind a wrapped frontend and reads its content-type definitions into the
|
|
4
|
+
* neutral Fimo schema shape — WITHOUT connecting to the CMS at runtime.
|
|
5
|
+
*
|
|
6
|
+
* The connector seam mirrors the framework-adapter contract: a CMS's name and
|
|
7
|
+
* quirks live ONLY under `scripts/cms/<cms>/`. Everything above (the registry,
|
|
8
|
+
* the example-content generator, the orchestrator wiring) is CMS-neutral. A
|
|
9
|
+
* CMS name appearing in neutral code is a review finding.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type DetectedFramework = 'next' | 'react-router' | 'remix' | 'astro' | 'nuxt' | 'sveltekit' | 'vue' | 'vite';
|
|
2
|
+
export interface FrameworkDetection {
|
|
3
|
+
framework: DetectedFramework | null;
|
|
4
|
+
/** For Next.js: the app-router directory (`app` or `src/app`) when present. */
|
|
5
|
+
appDir?: string;
|
|
6
|
+
/** For Next.js: the pages-router directory (`pages` or `src/pages`) when present. */
|
|
7
|
+
pagesDir?: string;
|
|
8
|
+
/** A recognized framework that wrap migration does not support yet. */
|
|
9
|
+
unsupported?: string;
|
|
10
|
+
/** For bare Vite: the project depends on react, so .jsx/.tsx is React JSX. */
|
|
11
|
+
react?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Detect the framework of an existing site from its package.json and layout.
|
|
15
|
+
* Used by `fimo init` (adopt-existing-site) and the wrap migration to decide
|
|
16
|
+
* how routes are discovered and which env flavor to write.
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectFramework(cwd: string): FrameworkDetection;
|
|
19
|
+
/** A frontend app found inside a workspace, adoptable by `fimo init`. */
|
|
20
|
+
export interface AdoptableApp {
|
|
21
|
+
/** Absolute directory of the app. */
|
|
22
|
+
dir: string;
|
|
23
|
+
/** Directory relative to the scan root (for display + as the init dirArg). */
|
|
24
|
+
relDir: string;
|
|
25
|
+
detection: FrameworkDetection;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Find frontend apps to adopt anywhere inside a directory tree. Most real
|
|
29
|
+
* sites are monorepos where the framework app is NOT at the root and NOT
|
|
30
|
+
* necessarily under `apps/` (`frontend/`, `sites/web`, `packages/marketing`,
|
|
31
|
+
* …) — `detectFramework(root)` returns null and `fimo init` would wrongly
|
|
32
|
+
* scaffold a new project. This walks the tree up to a bounded depth, running
|
|
33
|
+
* `detectFramework` on every directory that has a package.json and pruning
|
|
34
|
+
* `node_modules`/build output, so it finds the app wherever it lives without
|
|
35
|
+
* relying on a naming convention or a workspace manifest. The root itself is
|
|
36
|
+
* excluded (the caller checks it directly); descent stops at the first
|
|
37
|
+
* framework match in a subtree (an app's own subdirs are not separate apps).
|
|
38
|
+
*/
|
|
39
|
+
export declare function findAdoptableApps(rootDir: string): AdoptableApp[];
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Detect the framework of an existing site from its package.json and layout.
|
|
5
|
+
* Used by `fimo init` (adopt-existing-site) and the wrap migration to decide
|
|
6
|
+
* how routes are discovered and which env flavor to write.
|
|
7
|
+
*/
|
|
8
|
+
export function detectFramework(cwd) {
|
|
9
|
+
const pkgPath = join(cwd, 'package.json');
|
|
10
|
+
if (!existsSync(pkgPath)) {
|
|
11
|
+
return { framework: null };
|
|
12
|
+
}
|
|
13
|
+
let pkg;
|
|
14
|
+
try {
|
|
15
|
+
pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return { framework: null };
|
|
19
|
+
}
|
|
20
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21
|
+
if (deps.next) {
|
|
22
|
+
const appDir = ['app', 'src/app'].find((dir) => existsSync(join(cwd, dir)));
|
|
23
|
+
const pagesDir = ['pages', 'src/pages'].find((dir) => existsSync(join(cwd, dir)));
|
|
24
|
+
return { framework: 'next', appDir, pagesDir };
|
|
25
|
+
}
|
|
26
|
+
if (deps['react-router'] || deps['@react-router/dev']) {
|
|
27
|
+
return { framework: 'react-router' };
|
|
28
|
+
}
|
|
29
|
+
if (deps['@remix-run/react']) {
|
|
30
|
+
const pagesDir = ['app/routes'].find((dir) => existsSync(join(cwd, dir)));
|
|
31
|
+
return { framework: 'remix', pagesDir };
|
|
32
|
+
}
|
|
33
|
+
if (deps.astro) {
|
|
34
|
+
const pagesDir = ['src/pages'].find((dir) => existsSync(join(cwd, dir)));
|
|
35
|
+
return { framework: 'astro', pagesDir };
|
|
36
|
+
}
|
|
37
|
+
if (deps.nuxt) {
|
|
38
|
+
// 'src/pages' covers the common custom srcDir (nuxt.config `srcDir: './src'`).
|
|
39
|
+
const pagesDir = ['pages', 'app/pages', 'src/pages'].find((dir) => existsSync(join(cwd, dir)));
|
|
40
|
+
return { framework: 'nuxt', pagesDir };
|
|
41
|
+
}
|
|
42
|
+
if (deps['@sveltejs/kit']) {
|
|
43
|
+
const pagesDir = ['src/routes'].find((dir) => existsSync(join(cwd, dir)));
|
|
44
|
+
return { framework: 'sveltekit', pagesDir };
|
|
45
|
+
}
|
|
46
|
+
if (deps.vue && deps.vite) {
|
|
47
|
+
return { framework: 'vue' };
|
|
48
|
+
}
|
|
49
|
+
if (deps.vite) {
|
|
50
|
+
// A react dependency guarantees the JSX runtime: the --apply codemod and
|
|
51
|
+
// react-router route discovery are safe. Bare vite (Solid, Preact, lit)
|
|
52
|
+
// stays hands-off.
|
|
53
|
+
return { framework: 'vite', react: Boolean(deps.react) };
|
|
54
|
+
}
|
|
55
|
+
// Known frameworks we can NAME but not wrap yet — lets `fimo init` route
|
|
56
|
+
// honestly instead of silently falling through to create-new.
|
|
57
|
+
const unsupportedByDep = [
|
|
58
|
+
['gatsby', 'Gatsby'],
|
|
59
|
+
['@angular/core', 'Angular'],
|
|
60
|
+
['@docusaurus/core', 'Docusaurus'],
|
|
61
|
+
['@11ty/eleventy', 'Eleventy'],
|
|
62
|
+
];
|
|
63
|
+
for (const [dep, name] of unsupportedByDep) {
|
|
64
|
+
if (deps[dep]) {
|
|
65
|
+
return { framework: null, unsupported: name };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { framework: null };
|
|
69
|
+
}
|
|
70
|
+
const WORKSPACE_SKIP = new Set([
|
|
71
|
+
'node_modules',
|
|
72
|
+
'.git',
|
|
73
|
+
'dist',
|
|
74
|
+
'build',
|
|
75
|
+
'out',
|
|
76
|
+
'.next',
|
|
77
|
+
'.nuxt',
|
|
78
|
+
'.svelte-kit',
|
|
79
|
+
'.turbo',
|
|
80
|
+
'.vercel',
|
|
81
|
+
'coverage',
|
|
82
|
+
]);
|
|
83
|
+
/** How deep below the root the scan looks for a framework app (`apps/ui` is
|
|
84
|
+
* depth 2, `packages/frontend/web` is depth 3). */
|
|
85
|
+
const MAX_SCAN_DEPTH = 3;
|
|
86
|
+
/**
|
|
87
|
+
* Find frontend apps to adopt anywhere inside a directory tree. Most real
|
|
88
|
+
* sites are monorepos where the framework app is NOT at the root and NOT
|
|
89
|
+
* necessarily under `apps/` (`frontend/`, `sites/web`, `packages/marketing`,
|
|
90
|
+
* …) — `detectFramework(root)` returns null and `fimo init` would wrongly
|
|
91
|
+
* scaffold a new project. This walks the tree up to a bounded depth, running
|
|
92
|
+
* `detectFramework` on every directory that has a package.json and pruning
|
|
93
|
+
* `node_modules`/build output, so it finds the app wherever it lives without
|
|
94
|
+
* relying on a naming convention or a workspace manifest. The root itself is
|
|
95
|
+
* excluded (the caller checks it directly); descent stops at the first
|
|
96
|
+
* framework match in a subtree (an app's own subdirs are not separate apps).
|
|
97
|
+
*/
|
|
98
|
+
export function findAdoptableApps(rootDir) {
|
|
99
|
+
const apps = [];
|
|
100
|
+
const walk = (dir, depth) => {
|
|
101
|
+
if (depth > MAX_SCAN_DEPTH) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (dir !== rootDir && existsSync(join(dir, 'package.json'))) {
|
|
105
|
+
const detection = detectFramework(dir);
|
|
106
|
+
if (detection.framework) {
|
|
107
|
+
apps.push({ dir, relDir: relative(rootDir, dir), detection });
|
|
108
|
+
return; // don't descend into an app's own subtree
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let entries;
|
|
112
|
+
try {
|
|
113
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
for (const entry of entries) {
|
|
119
|
+
if (entry.isDirectory() && !WORKSPACE_SKIP.has(entry.name) && !entry.name.startsWith('.')) {
|
|
120
|
+
walk(join(dir, entry.name), depth + 1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
walk(rootDir, 0);
|
|
125
|
+
// Shallower + apps/-conventional first (the most likely primary site), then
|
|
126
|
+
// alphabetical — the order the interactive picker presents them in.
|
|
127
|
+
return apps.sort((a, b) => {
|
|
128
|
+
const depthA = a.relDir.split('/').length;
|
|
129
|
+
const depthB = b.relDir.split('/').length;
|
|
130
|
+
const rank = (relDir) => (relDir.startsWith('apps/') ? 0 : 1);
|
|
131
|
+
return rank(a.relDir) - rank(b.relDir) || depthA - depthB || a.relDir.localeCompare(b.relDir);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, 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 { detectFramework } from './detect-framework.js';
|
|
6
|
+
let dir;
|
|
7
|
+
const project = (deps, dirs = []) => {
|
|
8
|
+
dir = mkdtempSync(join(tmpdir(), 'detect-framework-'));
|
|
9
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 't', dependencies: deps }));
|
|
10
|
+
for (const d of dirs) {
|
|
11
|
+
mkdirSync(join(dir, d), { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
return dir;
|
|
14
|
+
};
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
if (dir) {
|
|
17
|
+
rmSync(dir, { recursive: true, force: true });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
describe('detectFramework', () => {
|
|
21
|
+
it('detects next with the app dir', () => {
|
|
22
|
+
expect(detectFramework(project({ next: '^15.0.0' }, ['app']))).toEqual({ framework: 'next', appDir: 'app' });
|
|
23
|
+
expect(detectFramework(project({ next: '^15.0.0' }, ['src/app']))).toEqual({
|
|
24
|
+
framework: 'next',
|
|
25
|
+
appDir: 'src/app',
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
it('detects react-router and vite', () => {
|
|
29
|
+
expect(detectFramework(project({ 'react-router': '^7.0.0' })).framework).toBe('react-router');
|
|
30
|
+
expect(detectFramework(project({ vite: '^7.0.0' })).framework).toBe('vite');
|
|
31
|
+
});
|
|
32
|
+
it('prefers next over an incidental vite dep', () => {
|
|
33
|
+
expect(detectFramework(project({ next: '^15.0.0', vite: '^7.0.0' }, ['app'])).framework).toBe('next');
|
|
34
|
+
});
|
|
35
|
+
it('returns null without a package.json or known framework', () => {
|
|
36
|
+
expect(detectFramework(join(tmpdir(), 'nope-does-not-exist')).framework).toBeNull();
|
|
37
|
+
expect(detectFramework(project({ express: '^4.0.0' })).framework).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('unsupported framework naming', () => {
|
|
41
|
+
it('names still-unsupported frameworks; astro is now adoptable', async () => {
|
|
42
|
+
const { mkdtempSync, writeFileSync, rmSync } = await import('node:fs');
|
|
43
|
+
const { tmpdir } = await import('node:os');
|
|
44
|
+
const { join } = await import('node:path');
|
|
45
|
+
const dir = mkdtempSync(join(tmpdir(), 'detect-'));
|
|
46
|
+
try {
|
|
47
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify({ dependencies: { gatsby: '^5.0.0' } }));
|
|
48
|
+
const { detectFramework } = await import('./detect-framework.js');
|
|
49
|
+
expect(detectFramework(dir)).toEqual({ framework: null, unsupported: 'Gatsby' });
|
|
50
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify({ dependencies: { astro: '^5.0.0' } }));
|
|
51
|
+
expect(detectFramework(dir).framework).toBe('astro');
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
rmSync(dir, { recursive: true, force: true });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('findAdoptableApps (monorepo / nested detection)', () => {
|
|
59
|
+
const workspace = (files) => {
|
|
60
|
+
dir = mkdtempSync(join(tmpdir(), 'find-apps-'));
|
|
61
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
62
|
+
const full = join(dir, rel);
|
|
63
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
64
|
+
writeFileSync(full, content);
|
|
65
|
+
}
|
|
66
|
+
return dir;
|
|
67
|
+
};
|
|
68
|
+
const pkg = (deps) => JSON.stringify({ name: 'x', dependencies: deps });
|
|
69
|
+
it('finds a Next app nested under apps/ when the root has no framework', async () => {
|
|
70
|
+
const { findAdoptableApps } = await import('./detect-framework.js');
|
|
71
|
+
const root = workspace({
|
|
72
|
+
'package.json': JSON.stringify({ name: 'monorepo', workspaces: ['apps/*'] }),
|
|
73
|
+
'apps/ui/package.json': pkg({ next: '^15.0.0' }),
|
|
74
|
+
'apps/ui/app/page.tsx': 'export default () => null;',
|
|
75
|
+
'apps/strapi/package.json': pkg({ '@strapi/strapi': '^5.0.0' }),
|
|
76
|
+
});
|
|
77
|
+
const apps = findAdoptableApps(root);
|
|
78
|
+
expect(apps.map((a) => a.relDir)).toEqual(['apps/ui']);
|
|
79
|
+
expect(apps[0].detection.framework).toBe('next');
|
|
80
|
+
expect(apps[0].detection.appDir).toBe('app');
|
|
81
|
+
});
|
|
82
|
+
it('finds an app in a NON-conventional dir (frontend/web), 3 levels deep', async () => {
|
|
83
|
+
const { findAdoptableApps } = await import('./detect-framework.js');
|
|
84
|
+
const root = workspace({
|
|
85
|
+
'package.json': JSON.stringify({ name: 'r', private: true }),
|
|
86
|
+
'frontend/web/package.json': pkg({ astro: '^5.0.0' }),
|
|
87
|
+
});
|
|
88
|
+
const apps = findAdoptableApps(root);
|
|
89
|
+
expect(apps.map((a) => a.relDir)).toEqual(['frontend/web']);
|
|
90
|
+
expect(apps[0].detection.framework).toBe('astro');
|
|
91
|
+
});
|
|
92
|
+
it('returns several apps for the picker, apps/ first', async () => {
|
|
93
|
+
const { findAdoptableApps } = await import('./detect-framework.js');
|
|
94
|
+
const root = workspace({
|
|
95
|
+
'package.json': JSON.stringify({ name: 'r' }),
|
|
96
|
+
'apps/site/package.json': pkg({ next: '^15.0.0' }),
|
|
97
|
+
'packages/docs/package.json': pkg({ astro: '^5.0.0' }),
|
|
98
|
+
});
|
|
99
|
+
const apps = findAdoptableApps(root);
|
|
100
|
+
expect(apps.map((a) => a.relDir)).toEqual(['apps/site', 'packages/docs']);
|
|
101
|
+
});
|
|
102
|
+
it('prunes node_modules and does not descend into a matched app', async () => {
|
|
103
|
+
const { findAdoptableApps } = await import('./detect-framework.js');
|
|
104
|
+
const root = workspace({
|
|
105
|
+
'package.json': JSON.stringify({ name: 'r' }),
|
|
106
|
+
'apps/web/package.json': pkg({ next: '^15.0.0' }),
|
|
107
|
+
// a nested example inside the matched app must NOT be returned separately
|
|
108
|
+
'apps/web/examples/demo/package.json': pkg({ astro: '^5.0.0' }),
|
|
109
|
+
'node_modules/some-dep/package.json': pkg({ next: '^15.0.0' }),
|
|
110
|
+
});
|
|
111
|
+
const apps = findAdoptableApps(root);
|
|
112
|
+
expect(apps.map((a) => a.relDir)).toEqual(['apps/web']);
|
|
113
|
+
});
|
|
114
|
+
it('returns [] when nothing framework-shaped is found', async () => {
|
|
115
|
+
const { findAdoptableApps } = await import('./detect-framework.js');
|
|
116
|
+
const root = workspace({
|
|
117
|
+
'package.json': JSON.stringify({ name: 'r' }),
|
|
118
|
+
'apps/api/package.json': pkg({ '@strapi/strapi': '^5.0.0' }),
|
|
119
|
+
});
|
|
120
|
+
expect(findAdoptableApps(root)).toEqual([]);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SchemaDraft } from './draft-schemas.js';
|
|
2
|
+
import type { WrapScanResult } from './scan-wrappable.js';
|
|
3
|
+
export interface RowsFile {
|
|
4
|
+
draftUid: string;
|
|
5
|
+
source: string;
|
|
6
|
+
references: Record<string, {
|
|
7
|
+
target?: string;
|
|
8
|
+
targets?: string[];
|
|
9
|
+
by: 'slug';
|
|
10
|
+
many?: boolean;
|
|
11
|
+
}>;
|
|
12
|
+
rows: Array<Record<string, unknown>>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Stage rows for every draft. Drafts carry the inferred field types, the
|
|
16
|
+
* scan carries the raw rows (typedRows for in-code candidates; data files
|
|
17
|
+
* are re-read from disk for the full, untruncated dataset).
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeRowsStaging(rootDir: string, scan: WrapScanResult, drafts: SchemaDraft[]): number;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import YAML from 'yaml';
|
|
4
|
+
/**
|
|
5
|
+
* Machine-staged entry ROWS for every drafted collection: the deterministic
|
|
6
|
+
* transformation agents kept re-implementing by hand (media envelopes,
|
|
7
|
+
* richtext docs, slugs inside data), applied once by the machine. Reference
|
|
8
|
+
* fields keep their SOURCE values (slugs/names) and each file carries a
|
|
9
|
+
* references descriptor — the resolution to documentIds happens at seed
|
|
10
|
+
* time (agent-side maps today; server-side via the batch endpoint next).
|
|
11
|
+
*
|
|
12
|
+
* Output: `.fimo/migration/rows/<ProvisionalUid>.rows.json`
|
|
13
|
+
* { draftUid, source, references: { field: { target, by, many? } }, rows }
|
|
14
|
+
*
|
|
15
|
+
* Regenerated on every migrate run; `schemas adopt-drafts` rewrites
|
|
16
|
+
* draftUid and reference targets through the same renames it applies to the
|
|
17
|
+
* schema files.
|
|
18
|
+
*/
|
|
19
|
+
const MEDIA_PATH = /^\/(images|img|videos|video|media|assets|files|docs|documents)\//i;
|
|
20
|
+
const MEDIA_EXT = /\.(png|jpe?g|gif|webp|avif|svg|mp4|webm|mov|mp3|wav|pdf|zip|docx?)$/i;
|
|
21
|
+
function toRichTextDoc(text) {
|
|
22
|
+
const paragraphs = text
|
|
23
|
+
.split(/\n\n+/)
|
|
24
|
+
.map((paragraph) => paragraph.trim())
|
|
25
|
+
.filter(Boolean);
|
|
26
|
+
return {
|
|
27
|
+
type: 'doc',
|
|
28
|
+
content: paragraphs.map((paragraph) => ({
|
|
29
|
+
type: 'paragraph',
|
|
30
|
+
content: [{ type: 'text', text: paragraph }],
|
|
31
|
+
})),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function transformValue(fieldType, value) {
|
|
35
|
+
if (value == null) {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
if (fieldType === 'media' && typeof value === 'string' && (MEDIA_PATH.test(value) || MEDIA_EXT.test(value))) {
|
|
39
|
+
return { source: 'local', url: value, alt: '' };
|
|
40
|
+
}
|
|
41
|
+
if (fieldType === 'richtext' && typeof value === 'string') {
|
|
42
|
+
return toRichTextDoc(value);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function loadSourceRows(rootDir, source) {
|
|
47
|
+
const filePath = join(rootDir, source);
|
|
48
|
+
if (!existsSync(filePath)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
53
|
+
const parsed = /\.ya?ml$/.test(source) ? YAML.parse(raw) : JSON.parse(raw);
|
|
54
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stage rows for every draft. Drafts carry the inferred field types, the
|
|
62
|
+
* scan carries the raw rows (typedRows for in-code candidates; data files
|
|
63
|
+
* are re-read from disk for the full, untruncated dataset).
|
|
64
|
+
*/
|
|
65
|
+
export function writeRowsStaging(rootDir, scan, drafts) {
|
|
66
|
+
const rowsDir = join(rootDir, '.fimo', 'migration', 'rows');
|
|
67
|
+
rmSync(rowsDir, { recursive: true, force: true });
|
|
68
|
+
if (drafts.length === 0) {
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
const bySourceLabel = new Map(drafts.map((draft) => [draft.source, draft]));
|
|
72
|
+
const provisionalByName = new Map(drafts.map((draft) => [draft.sourceName, draft.uid]));
|
|
73
|
+
const toProvisional = (name) => provisionalByName.get(name) ?? name;
|
|
74
|
+
let written = 0;
|
|
75
|
+
const stage = (draft, source, rawRows, references) => {
|
|
76
|
+
const fieldTypes = new Map(Object.entries(draft.fields).map(([name, def]) => [
|
|
77
|
+
name,
|
|
78
|
+
def && typeof def === 'object' ? (def.type ?? 'string') : 'string',
|
|
79
|
+
]));
|
|
80
|
+
const referenceFields = new Set(references.map((reference) => reference.field));
|
|
81
|
+
const rows = rawRows.map((row) => {
|
|
82
|
+
const out = {};
|
|
83
|
+
for (const [key, value] of Object.entries(row)) {
|
|
84
|
+
// Reference values stay as SOURCE values for later resolution.
|
|
85
|
+
out[key] = referenceFields.has(key) ? value : transformValue(fieldTypes.get(key), value);
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
});
|
|
89
|
+
const descriptor = {};
|
|
90
|
+
for (const reference of references) {
|
|
91
|
+
const targets = reference.targets.map(toProvisional);
|
|
92
|
+
descriptor[reference.field] = {
|
|
93
|
+
...(targets.length > 1 ? { targets } : { target: targets[0] }),
|
|
94
|
+
by: 'slug',
|
|
95
|
+
...(reference.many ? { many: true } : {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
mkdirSync(rowsDir, { recursive: true });
|
|
99
|
+
writeFileSync(join(rowsDir, `${draft.uid}.rows.json`), `${JSON.stringify({ draftUid: draft.uid, source, references: descriptor, rows }, null, 1)}\n`);
|
|
100
|
+
written += 1;
|
|
101
|
+
};
|
|
102
|
+
for (const candidate of scan.collections) {
|
|
103
|
+
const label = `${candidate.file}:${candidate.line}`;
|
|
104
|
+
const draft = bySourceLabel.get(label);
|
|
105
|
+
if (!draft || !candidate.typedRows || candidate.typedRows.length === 0) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
stage(draft, label, candidate.typedRows, (candidate.references ?? []).map((reference) => ({
|
|
109
|
+
field: reference.field,
|
|
110
|
+
targets: reference.targets,
|
|
111
|
+
many: reference.many,
|
|
112
|
+
})));
|
|
113
|
+
}
|
|
114
|
+
for (const dataFile of scan.dataFiles) {
|
|
115
|
+
const draft = bySourceLabel.get(dataFile.file);
|
|
116
|
+
if (!draft) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// Markdown groups can't be re-read from a single path (`<dir>/*.md`) — the
|
|
120
|
+
// scanner already parsed every document into the collection's typedRows.
|
|
121
|
+
const rawRows = dataFile.kind === 'markdown'
|
|
122
|
+
? (dataFile.collections[0]?.typedRows ?? null)
|
|
123
|
+
: loadSourceRows(rootDir, dataFile.file);
|
|
124
|
+
if (!rawRows) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const references = dataFile.collections.flatMap((collection) => (collection.references ?? []).map((reference) => ({
|
|
128
|
+
field: reference.field,
|
|
129
|
+
targets: reference.targets,
|
|
130
|
+
many: reference.many,
|
|
131
|
+
})));
|
|
132
|
+
stage(draft, dataFile.file, rawRows, references);
|
|
133
|
+
}
|
|
134
|
+
return written;
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|