meno-core 1.0.52 → 1.0.54
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/.claude/settings.local.json +1 -3
- package/bin/cli.ts +48 -57
- package/build-astro.ts +296 -108
- package/build-next.ts +1374 -0
- package/build-static.test.ts +39 -10
- package/build-static.ts +127 -127
- package/dist/bin/cli.js +34 -38
- package/dist/bin/cli.js.map +2 -2
- package/dist/build-static.js +12 -11
- package/dist/chunks/chunk-2AR55GYH.js +42 -0
- package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
- package/dist/chunks/{chunk-CXCBV2M7.js → chunk-2FN4UOVO.js} +581 -502
- package/dist/chunks/chunk-2FN4UOVO.js.map +7 -0
- package/dist/chunks/chunk-3XER4E5W.js +168 -0
- package/dist/chunks/chunk-3XER4E5W.js.map +7 -0
- package/dist/chunks/chunk-5ETZFREW.js +514 -0
- package/dist/chunks/chunk-5ETZFREW.js.map +7 -0
- package/dist/chunks/{chunk-2MHDV5BF.js → chunk-7E4IF5L7.js} +15 -21
- package/dist/chunks/chunk-7E4IF5L7.js.map +7 -0
- package/dist/chunks/{chunk-7NIC4I3V.js → chunk-7HWQUVTU.js} +1691 -1316
- package/dist/chunks/chunk-7HWQUVTU.js.map +7 -0
- package/dist/chunks/{chunk-EDQSMAMP.js → chunk-AE3QK5QW.js} +189 -19
- package/dist/chunks/chunk-AE3QK5QW.js.map +7 -0
- package/dist/chunks/{chunk-HNLUO36W.js → chunk-F6KTJYGV.js} +8 -8
- package/dist/chunks/chunk-F6KTJYGV.js.map +7 -0
- package/dist/chunks/{chunk-WQFG7PAH.js → chunk-FZITJSSS.js} +2 -6
- package/dist/chunks/chunk-FZITJSSS.js.map +7 -0
- package/dist/chunks/{chunk-H4JSCDNW.js → chunk-GSYYA5GX.js} +25 -2
- package/dist/chunks/chunk-GSYYA5GX.js.map +7 -0
- package/dist/chunks/{chunk-2QK6U5UK.js → chunk-HIZMY3EP.js} +12 -2
- package/dist/chunks/chunk-HIZMY3EP.js.map +7 -0
- package/dist/chunks/{chunk-AZQYF6KE.js → chunk-I2WEGYA7.js} +41 -176
- package/dist/chunks/chunk-I2WEGYA7.js.map +7 -0
- package/dist/chunks/{chunk-I7YIGZXT.js → chunk-JNO3CNLJ.js} +6 -9
- package/dist/chunks/chunk-JNO3CNLJ.js.map +7 -0
- package/dist/chunks/{chunk-UB44F4Z2.js → chunk-NVRBTSQG.js} +2 -4
- package/dist/chunks/chunk-NVRBTSQG.js.map +7 -0
- package/dist/chunks/{chunk-LHLHPYSP.js → chunk-Q4OBWKXG.js} +48 -40
- package/dist/chunks/chunk-Q4OBWKXG.js.map +7 -0
- package/dist/chunks/{chunk-A725KYFK.js → chunk-QTE32Y53.js} +780 -323
- package/dist/chunks/chunk-QTE32Y53.js.map +7 -0
- package/dist/chunks/{chunk-LPVETICS.js → chunk-STDY3OVM.js} +397 -84
- package/dist/chunks/chunk-STDY3OVM.js.map +7 -0
- package/dist/chunks/configService-PRJZF7Y6.js +14 -0
- package/dist/chunks/{constants-GWBAD66U.js → constants-KIQEYMAM.js} +2 -2
- package/dist/chunks/{fs-JGINUXGL.js → fs-ZI5JEU7V.js} +2 -2
- package/dist/entries/server-router.js +14 -19
- package/dist/entries/server-router.js.map +2 -2
- package/dist/lib/client/index.js +957 -356
- package/dist/lib/client/index.js.map +4 -4
- package/dist/lib/server/index.js +1538 -328
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +277 -73
- package/dist/lib/shared/index.js.map +4 -4
- package/dist/lib/shared/richtext/index.js +1 -1
- package/dist/lib/test-utils/index.js +38 -60
- package/dist/lib/test-utils/index.js.map +2 -2
- package/entries/client-router.tsx +14 -172
- package/entries/server-router.tsx +1 -7
- package/lib/client/ClientInitializer.ts +8 -8
- package/lib/client/ErrorBoundary.test.tsx +156 -151
- package/lib/client/ErrorBoundary.tsx +184 -121
- package/lib/client/componentRegistry.test.ts +96 -108
- package/lib/client/componentRegistry.ts +1 -2
- package/lib/client/contexts/ThemeContext.tsx +3 -2
- package/lib/client/core/ComponentBuilder.test.ts +513 -560
- package/lib/client/core/ComponentBuilder.ts +335 -146
- package/lib/client/core/ComponentRenderer.test.tsx +1 -2
- package/lib/client/core/ComponentRenderer.tsx +46 -33
- package/lib/client/core/builders/embedBuilder.ts +246 -54
- package/lib/client/core/builders/linkBuilder.ts +71 -44
- package/lib/client/core/builders/linkNodeBuilder.ts +78 -53
- package/lib/client/core/builders/listBuilder.ts +137 -89
- package/lib/client/core/builders/localeListBuilder.ts +95 -60
- package/lib/client/core/builders/types.ts +5 -5
- package/lib/client/core/cmsTemplateProcessor.ts +7 -7
- package/lib/client/elementRegistry.ts +3 -3
- package/lib/client/fontFamiliesService.test.ts +68 -0
- package/lib/client/fontFamiliesService.ts +69 -0
- package/lib/client/hmr/HMRManager.tsx +8 -0
- package/lib/client/hmrCssReload.ts +166 -0
- package/lib/client/hmrWebSocket.ts +9 -14
- package/lib/client/hooks/useColorVariables.test.ts +21 -21
- package/lib/client/hooks/useColorVariables.ts +14 -10
- package/lib/client/hooks/usePropertyAutocomplete.ts +3 -5
- package/lib/client/hooks/useVariables.ts +4 -4
- package/lib/client/hydration/HydrationUtils.test.ts +24 -25
- package/lib/client/hydration/HydrationUtils.ts +3 -4
- package/lib/client/i18nConfigService.test.ts +2 -7
- package/lib/client/i18nConfigService.ts +2 -2
- package/lib/client/index.ts +4 -0
- package/lib/client/meno-filter/MenoFilter.test.ts +19 -21
- package/lib/client/meno-filter/MenoFilter.ts +5 -9
- package/lib/client/meno-filter/bindings.ts +15 -40
- package/lib/client/meno-filter/init.ts +1 -1
- package/lib/client/meno-filter/renderer.ts +23 -29
- package/lib/client/meno-filter/script.generated.ts +1 -3
- package/lib/client/meno-filter/ui.ts +5 -5
- package/lib/client/meno-filter/updates.ts +15 -21
- package/lib/client/navigation.test.ts +159 -159
- package/lib/client/navigation.ts +0 -1
- package/lib/client/responsiveStyleResolver.test.ts +230 -228
- package/lib/client/responsiveStyleResolver.ts +13 -16
- package/lib/client/routing/RouteLoader.test.ts +25 -26
- package/lib/client/routing/RouteLoader.ts +30 -37
- package/lib/client/routing/Router.tsx +112 -18
- package/lib/client/scripts/ScriptExecutor.test.ts +270 -128
- package/lib/client/scripts/ScriptExecutor.ts +69 -33
- package/lib/client/services/PrefetchService.test.ts +2 -2
- package/lib/client/services/PrefetchService.ts +10 -24
- package/lib/client/styleProcessor.test.ts +9 -9
- package/lib/client/styleProcessor.ts +18 -15
- package/lib/client/styles/StyleInjector.test.ts +122 -115
- package/lib/client/styles/StyleInjector.ts +25 -7
- package/lib/client/styles/UtilityClassCollector.ts +26 -27
- package/lib/client/styles/cspNonce.test.ts +64 -0
- package/lib/client/styles/cspNonce.ts +63 -0
- package/lib/client/templateEngine.test.ts +600 -448
- package/lib/client/templateEngine.ts +205 -64
- package/lib/client/theme.ts +0 -1
- package/lib/client/utils/toast.ts +0 -1
- package/lib/server/__integration__/api-routes.test.ts +8 -4
- package/lib/server/__integration__/cms-integration.test.ts +1 -4
- package/lib/server/__integration__/server-lifecycle.test.ts +2 -5
- package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
- package/lib/server/__integration__/static-assets.test.ts +1 -1
- package/lib/server/__integration__/test-helpers.ts +84 -70
- package/lib/server/ab/generateFunctions.ts +12 -10
- package/lib/server/astro/cmsPageEmitter.ts +47 -32
- package/lib/server/astro/componentEmitter.ts +82 -37
- package/lib/server/astro/cssCollector.ts +10 -26
- package/lib/server/astro/nodeToAstro.test.ts +1750 -30
- package/lib/server/astro/nodeToAstro.ts +327 -178
- package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +260 -0
- package/lib/server/astro/normalizeOrphanTemplateProps.ts +176 -0
- package/lib/server/astro/pageEmitter.ts +9 -13
- package/lib/server/astro/tailwindMapper.test.ts +10 -37
- package/lib/server/astro/tailwindMapper.ts +33 -40
- package/lib/server/astro/templateTransformer.ts +14 -17
- package/lib/server/createServer.ts +16 -17
- package/lib/server/cssGenerator.test.ts +35 -44
- package/lib/server/cssGenerator.ts +6 -17
- package/lib/server/draftPageStore.ts +49 -0
- package/lib/server/fileWatcher.test.ts +124 -10
- package/lib/server/fileWatcher.ts +164 -98
- package/lib/server/index.ts +20 -2
- package/lib/server/jsonLoader.test.ts +39 -2
- package/lib/server/jsonLoader.ts +33 -31
- package/lib/server/middleware/cors.test.ts +20 -20
- package/lib/server/middleware/cors.ts +28 -4
- package/lib/server/middleware/errorHandler.test.ts +5 -3
- package/lib/server/middleware/errorHandler.ts +3 -8
- package/lib/server/middleware/index.ts +0 -1
- package/lib/server/middleware/logger.test.ts +7 -5
- package/lib/server/middleware/logger.ts +10 -22
- package/lib/server/pageCache.test.ts +76 -77
- package/lib/server/pageCache.ts +0 -1
- package/lib/server/projectContext.ts +4 -3
- package/lib/server/providers/fileSystemCMSProvider.test.ts +124 -95
- package/lib/server/providers/fileSystemCMSProvider.ts +35 -20
- package/lib/server/providers/fileSystemPageProvider.test.ts +84 -0
- package/lib/server/providers/fileSystemPageProvider.ts +39 -12
- package/lib/server/routes/api/cms.test.ts +26 -14
- package/lib/server/routes/api/cms.ts +9 -14
- package/lib/server/routes/api/components.ts +35 -34
- package/lib/server/routes/api/config.ts +0 -1
- package/lib/server/routes/api/core-routes.ts +49 -76
- package/lib/server/routes/api/functions.ts +8 -16
- package/lib/server/routes/api/index.ts +3 -6
- package/lib/server/routes/api/pages.ts +21 -32
- package/lib/server/routes/api/shared.test.ts +1 -1
- package/lib/server/routes/api/shared.ts +65 -6
- package/lib/server/routes/api/variables.test.ts +1 -3
- package/lib/server/routes/api/variables.ts +1 -1
- package/lib/server/routes/index.ts +106 -19
- package/lib/server/routes/pages.ts +47 -35
- package/lib/server/routes/static.ts +16 -4
- package/lib/server/runtime/bundler.ts +47 -32
- package/lib/server/runtime/fs.ts +3 -13
- package/lib/server/runtime/httpServer.ts +5 -9
- package/lib/server/services/ColorService.ts +32 -27
- package/lib/server/services/EnumService.test.ts +2 -6
- package/lib/server/services/EnumService.ts +7 -2
- package/lib/server/services/VariableService.test.ts +1 -5
- package/lib/server/services/VariableService.ts +6 -1
- package/lib/server/services/cmsService.test.ts +116 -78
- package/lib/server/services/cmsService.ts +24 -54
- package/lib/server/services/componentService.test.ts +303 -20
- package/lib/server/services/componentService.ts +397 -76
- package/lib/server/services/configService.test.ts +9 -31
- package/lib/server/services/configService.ts +20 -27
- package/lib/server/services/fileWatcherService.ts +44 -30
- package/lib/server/services/index.ts +0 -1
- package/lib/server/services/pageService.test.ts +24 -3
- package/lib/server/services/pageService.ts +135 -16
- package/lib/server/ssr/attributeBuilder.ts +24 -8
- package/lib/server/ssr/buildErrorOverlay.ts +12 -13
- package/lib/server/ssr/clientDataInjector.ts +7 -21
- package/lib/server/ssr/cmsSSRProcessor.ts +3 -6
- package/lib/server/ssr/cssCollector.ts +1 -1
- package/lib/server/ssr/errorOverlay.test.ts +21 -2
- package/lib/server/ssr/errorOverlay.ts +39 -18
- package/lib/server/ssr/htmlGenerator.nonce.test.ts +3 -9
- package/lib/server/ssr/htmlGenerator.test.ts +173 -56
- package/lib/server/ssr/htmlGenerator.ts +191 -112
- package/lib/server/ssr/imageMetadata.test.ts +3 -1
- package/lib/server/ssr/imageMetadata.ts +25 -19
- package/lib/server/ssr/jsCollector.test.ts +3 -13
- package/lib/server/ssr/jsCollector.ts +3 -8
- package/lib/server/ssr/liveReloadIntegration.test.ts +184 -22
- package/lib/server/ssr/metaTagGenerator.ts +2 -2
- package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
- package/lib/server/ssr/ssrRenderer.test.ts +263 -246
- package/lib/server/ssr/ssrRenderer.ts +700 -231
- package/lib/server/ssrRenderer.test.ts +1044 -950
- package/lib/server/utils/jsonLineMapper.test.ts +28 -28
- package/lib/server/utils/jsonLineMapper.ts +1 -1
- package/lib/server/validateStyleCoverage.ts +18 -20
- package/lib/server/webflow/buildWebflow.ts +41 -53
- package/lib/server/webflow/nodeToWebflow.test.ts +150 -218
- package/lib/server/webflow/nodeToWebflow.ts +195 -258
- package/lib/server/webflow/styleMapper.test.ts +15 -56
- package/lib/server/webflow/styleMapper.ts +33 -41
- package/lib/server/webflow/types.ts +1 -8
- package/lib/server/websocketManager.ts +16 -20
- package/lib/shared/attributeNodeUtils.test.ts +15 -15
- package/lib/shared/attributeNodeUtils.ts +5 -12
- package/lib/shared/breakpoints.ts +4 -11
- package/lib/shared/cmsQueryParser.test.ts +50 -42
- package/lib/shared/cmsQueryParser.ts +49 -31
- package/lib/shared/colorVariableUtils.test.ts +5 -5
- package/lib/shared/colorVariableUtils.ts +3 -8
- package/lib/shared/componentRefs.ts +41 -0
- package/lib/shared/constants.test.ts +3 -3
- package/lib/shared/constants.ts +12 -8
- package/lib/shared/cssGeneration.test.ts +262 -144
- package/lib/shared/cssGeneration.ts +189 -514
- package/lib/shared/cssNamedColors.ts +152 -30
- package/lib/shared/cssProperties.test.ts +5 -6
- package/lib/shared/cssProperties.ts +479 -111
- package/lib/shared/elementClassName.test.ts +109 -109
- package/lib/shared/elementClassName.ts +1 -1
- package/lib/shared/elementUtils.ts +12 -16
- package/lib/shared/errorLogger.ts +2 -10
- package/lib/shared/errors.test.ts +2 -13
- package/lib/shared/errors.ts +2 -8
- package/lib/shared/expressionEvaluator.test.ts +119 -0
- package/lib/shared/expressionEvaluator.ts +95 -22
- package/lib/shared/fontCss.ts +101 -0
- package/lib/shared/fontLoader.test.ts +19 -5
- package/lib/shared/fontLoader.ts +8 -86
- package/lib/shared/friendlyError.test.ts +87 -0
- package/lib/shared/friendlyError.ts +120 -0
- package/lib/shared/gradientUtils.test.ts +1 -5
- package/lib/shared/gradientUtils.ts +2 -6
- package/lib/shared/hrefRefs.test.ts +130 -0
- package/lib/shared/hrefRefs.ts +92 -0
- package/lib/shared/i18n.test.ts +1 -1
- package/lib/shared/i18n.ts +13 -34
- package/lib/shared/index.ts +56 -0
- package/lib/shared/inlineSvgStyleRules.test.ts +108 -0
- package/lib/shared/inlineSvgStyleRules.ts +132 -0
- package/lib/shared/interactiveStyleMappings.test.ts +11 -33
- package/lib/shared/interactiveStyleMappings.ts +9 -16
- package/lib/shared/interactiveStyles.test.ts +165 -188
- package/lib/shared/interfaces/contentProvider.ts +14 -1
- package/lib/shared/itemTemplateUtils.test.ts +20 -12
- package/lib/shared/itemTemplateUtils.ts +23 -36
- package/lib/shared/jsonRepair.ts +8 -2
- package/lib/shared/libraryLoader.test.ts +15 -49
- package/lib/shared/libraryLoader.ts +7 -22
- package/lib/shared/netlifyLocale404.test.ts +179 -0
- package/lib/shared/netlifyLocale404.ts +110 -0
- package/lib/shared/nodeUtils.test.ts +24 -16
- package/lib/shared/nodeUtils.ts +49 -19
- package/lib/shared/pathArrayUtils.test.ts +1 -2
- package/lib/shared/pathArrayUtils.ts +1 -1
- package/lib/shared/pathSecurity.ts +1 -1
- package/lib/shared/pathUtils.test.ts +4 -6
- package/lib/shared/pathUtils.ts +42 -48
- package/lib/shared/paths/Path.test.ts +2 -2
- package/lib/shared/paths/Path.ts +0 -1
- package/lib/shared/paths/PathConverter.test.ts +1 -1
- package/lib/shared/paths/PathConverter.ts +14 -17
- package/lib/shared/paths/PathUtils.ts +9 -10
- package/lib/shared/paths/PathValidator.test.ts +2 -15
- package/lib/shared/paths/PathValidator.ts +11 -9
- package/lib/shared/paths/index.ts +1 -2
- package/lib/shared/propResolver.test.ts +240 -244
- package/lib/shared/propResolver.ts +14 -25
- package/lib/shared/pxToRem.test.ts +7 -6
- package/lib/shared/pxToRem.ts +2 -5
- package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +9 -5
- package/lib/shared/registry/ClientRegistry.ts +0 -1
- package/lib/shared/registry/ComponentRegistry.test.ts +43 -29
- package/lib/shared/registry/ComponentRegistry.ts +9 -11
- package/lib/shared/registry/NodeTypeDefinition.ts +15 -8
- package/lib/shared/registry/RegistryManager.ts +1 -2
- package/lib/shared/registry/SSRRegistry.ts +0 -1
- package/lib/shared/registry/createNodeType.ts +7 -9
- package/lib/shared/registry/defineNodeType.ts +2 -6
- package/lib/shared/registry/index.ts +0 -1
- package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
- package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
- package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +47 -18
- package/lib/shared/registry/nodeTypes/LinkNodeType.ts +22 -20
- package/lib/shared/registry/nodeTypes/ListNodeType.ts +78 -74
- package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
- package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +6 -7
- package/lib/shared/registry/nodeTypes/index.ts +10 -2
- package/lib/shared/responsiveScaling.test.ts +15 -31
- package/lib/shared/responsiveScaling.ts +55 -37
- package/lib/shared/responsiveStyleUtils.ts +11 -13
- package/lib/shared/richtext/htmlToTiptap.test.ts +23 -14
- package/lib/shared/richtext/htmlToTiptap.ts +1 -3
- package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
- package/lib/shared/richtext/types.ts +1 -8
- package/lib/shared/slugTranslator.test.ts +37 -13
- package/lib/shared/slugTranslator.ts +31 -11
- package/lib/shared/slugify.ts +9 -15
- package/lib/shared/styleNodeUtils.test.ts +8 -8
- package/lib/shared/styleNodeUtils.ts +9 -11
- package/lib/shared/styleUtils.test.ts +87 -61
- package/lib/shared/styleUtils.ts +5 -6
- package/lib/shared/themeDefaults.test.ts +11 -11
- package/lib/shared/themeDefaults.ts +3 -4
- package/lib/shared/tree/PathBuilder.test.ts +160 -109
- package/lib/shared/tree/PathBuilder.ts +121 -59
- package/lib/shared/treePathUtils.test.ts +2 -10
- package/lib/shared/treePathUtils.ts +54 -59
- package/lib/shared/types/api.ts +1 -2
- package/lib/shared/types/cms.ts +25 -21
- package/lib/shared/types/comment.ts +132 -0
- package/lib/shared/types/components.ts +27 -25
- package/lib/shared/types/errors.test.ts +1 -6
- package/lib/shared/types/errors.ts +3 -7
- package/lib/shared/types/experiments.ts +28 -28
- package/lib/shared/types/index.ts +14 -2
- package/lib/shared/types/rendering.ts +8 -0
- package/lib/shared/types/styles.ts +0 -1
- package/lib/shared/types/variables.test.ts +4 -13
- package/lib/shared/types/variables.ts +48 -27
- package/lib/shared/types.ts +1 -2
- package/lib/shared/utilityClassConfig.ts +648 -319
- package/lib/shared/utilityClassMapper.test.ts +213 -78
- package/lib/shared/utilityClassMapper.ts +188 -246
- package/lib/shared/utilityClassNames.ts +326 -0
- package/lib/shared/utils.test.ts +2 -10
- package/lib/shared/utils.ts +19 -10
- package/lib/shared/validation/cmsValidators.ts +2 -1
- package/lib/shared/validation/commentValidators.test.ts +53 -0
- package/lib/shared/validation/commentValidators.ts +80 -0
- package/lib/shared/validation/index.ts +1 -0
- package/lib/shared/validation/propValidator.test.ts +18 -20
- package/lib/shared/validation/propValidator.ts +12 -17
- package/lib/shared/validation/schemas.test.ts +24 -33
- package/lib/shared/validation/schemas.ts +469 -344
- package/lib/shared/validation/validators.test.ts +1 -6
- package/lib/shared/validation/validators.ts +89 -68
- package/lib/shared/viewportUnits.integration.test.ts +46 -0
- package/lib/shared/viewportUnits.test.ts +91 -0
- package/lib/shared/viewportUnits.ts +63 -0
- package/lib/test-utils/dom-setup.ts +7 -1
- package/lib/test-utils/factories/ConsoleMockFactory.ts +3 -7
- package/lib/test-utils/factories/DomMockFactory.ts +7 -19
- package/lib/test-utils/factories/EventMockFactory.ts +7 -13
- package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
- package/lib/test-utils/factories/ServerMockFactory.ts +5 -9
- package/lib/test-utils/factories/StoreMockFactory.ts +14 -25
- package/lib/test-utils/fixtures.ts +45 -45
- package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
- package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
- package/lib/test-utils/helpers.ts +1 -5
- package/lib/test-utils/index.ts +0 -4
- package/lib/test-utils/mockFactories.ts +12 -18
- package/lib/test-utils/mocks.ts +4 -2
- package/package.json +1 -1
- package/scripts/build-meno-filter.ts +1 -4
- package/vite.config.ts +4 -4
- package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
- package/dist/chunks/chunk-2QK6U5UK.js.map +0 -7
- package/dist/chunks/chunk-7NIC4I3V.js.map +0 -7
- package/dist/chunks/chunk-A725KYFK.js.map +0 -7
- package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
- package/dist/chunks/chunk-CXCBV2M7.js.map +0 -7
- package/dist/chunks/chunk-EDQSMAMP.js.map +0 -7
- package/dist/chunks/chunk-H4JSCDNW.js.map +0 -7
- package/dist/chunks/chunk-HNLUO36W.js.map +0 -7
- package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
- package/dist/chunks/chunk-J23ZX5AP.js +0 -241
- package/dist/chunks/chunk-J23ZX5AP.js.map +0 -7
- package/dist/chunks/chunk-LHLHPYSP.js.map +0 -7
- package/dist/chunks/chunk-LPVETICS.js.map +0 -7
- package/dist/chunks/chunk-UB44F4Z2.js.map +0 -7
- package/dist/chunks/chunk-WQFG7PAH.js.map +0 -7
- package/dist/chunks/configService-R3OGU2UD.js +0 -13
- /package/dist/chunks/{configService-R3OGU2UD.js.map → configService-PRJZF7Y6.js.map} +0 -0
- /package/dist/chunks/{constants-GWBAD66U.js.map → constants-KIQEYMAM.js.map} +0 -0
- /package/dist/chunks/{fs-JGINUXGL.js.map → fs-ZI5JEU7V.js.map} +0 -0
package/build-astro.ts
CHANGED
|
@@ -4,45 +4,54 @@
|
|
|
4
4
|
* with a shared layout, global CSS, and optional CMS content collections.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, writeFileSync } from
|
|
8
|
-
import { writeFile, readFile } from
|
|
9
|
-
import { join } from
|
|
10
|
-
import { createHash } from
|
|
7
|
+
import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, writeFileSync } from 'fs';
|
|
8
|
+
import { writeFile, readFile } from 'fs/promises';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { createHash } from 'crypto';
|
|
11
11
|
import { inspect, minifyJS as runtimeMinifyJS } from './lib/server/runtime';
|
|
12
12
|
import {
|
|
13
13
|
loadJSONFile,
|
|
14
14
|
loadComponentDirectory,
|
|
15
15
|
mapPageNameToPath,
|
|
16
16
|
parseJSON,
|
|
17
|
-
loadI18nConfig
|
|
18
|
-
} from
|
|
19
|
-
import { generateSSRHTML } from
|
|
20
|
-
import type { SSRHTMLResult } from
|
|
21
|
-
import { projectPaths } from
|
|
22
|
-
import { loadProjectConfig, generateFontCSS, generateFontPreloadTags } from
|
|
23
|
-
import { FileSystemCMSProvider } from
|
|
24
|
-
import { CMSService } from
|
|
25
|
-
import { isI18nValue, resolveI18nValue } from
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import {
|
|
29
|
-
import type {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
17
|
+
loadI18nConfig,
|
|
18
|
+
} from './lib/server/jsonLoader';
|
|
19
|
+
import { generateSSRHTML } from './lib/server/ssrRenderer';
|
|
20
|
+
import type { SSRHTMLResult } from './lib/server/ssr/htmlGenerator';
|
|
21
|
+
import { projectPaths } from './lib/server/projectContext';
|
|
22
|
+
import { loadProjectConfig, generateFontCSS, generateFontPreloadTags } from './lib/shared/fontLoader';
|
|
23
|
+
import { FileSystemCMSProvider } from './lib/server/providers/fileSystemCMSProvider';
|
|
24
|
+
import { CMSService } from './lib/server/services/cmsService';
|
|
25
|
+
import { isI18nValue, resolveI18nValue } from './lib/shared/i18n';
|
|
26
|
+
import { syncNetlifyLocale404Block } from './lib/shared/netlifyLocale404';
|
|
27
|
+
import { tiptapToHtml } from './lib/shared/richtext/tiptapToHtml';
|
|
28
|
+
import { isTiptapDocument } from './lib/shared/richtext/types';
|
|
29
|
+
import type { ComponentDefinition, JSONPage, CMSSchema, CMSItem, I18nConfig } from './lib/shared/types';
|
|
30
|
+
import type { CMSFieldDefinition } from './lib/shared/types/cms';
|
|
31
|
+
import { isItemDraftForLocale } from './lib/shared/types';
|
|
32
|
+
import { CMS_DRAFT_SUFFIX } from './lib/shared/pathSecurity';
|
|
33
|
+
import type { SlugMap } from './lib/shared/slugTranslator';
|
|
34
|
+
import { renderPageSSR } from './lib/server/ssr/ssrRenderer';
|
|
35
|
+
import { generateThemeColorVariablesCSS, generateVariablesCSS } from './lib/server/cssGenerator';
|
|
36
|
+
import { colorService } from './lib/server/services/ColorService';
|
|
37
|
+
import { variableService } from './lib/server/services/VariableService';
|
|
38
|
+
import { configService } from './lib/server/services/configService';
|
|
39
|
+
import { loadBreakpointConfig, loadIconsConfig } from './lib/server/jsonLoader';
|
|
40
|
+
import type { InteractiveStyles } from './lib/shared/types/styles';
|
|
41
|
+
import {
|
|
42
|
+
collectComponentLibraries,
|
|
43
|
+
filterLibrariesByContext,
|
|
44
|
+
mergeLibraries,
|
|
45
|
+
generateLibraryTags,
|
|
46
|
+
} from './lib/shared/libraryLoader';
|
|
47
|
+
import { migrateTemplatesDirectory } from './lib/server/migrateTemplates';
|
|
48
|
+
import { emitAstroComponent } from './lib/server/astro/componentEmitter';
|
|
49
|
+
import { emitAstroPage } from './lib/server/astro/pageEmitter';
|
|
50
|
+
import { normalizeOrphanTemplateProps } from './lib/server/astro/normalizeOrphanTemplateProps';
|
|
51
|
+
import { emitCMSPage, CMS_SLUG_PLACEHOLDER } from './lib/server/astro/cmsPageEmitter';
|
|
52
|
+
import { collectAllMappingClasses } from './lib/server/astro/cssCollector';
|
|
53
|
+
import { buildImageMetadataMap, RESPONSIVE_WIDTHS } from './lib/server/ssr/imageMetadata';
|
|
54
|
+
import { needsFormHandler, formHandlerScript } from './lib/client/scripts/formHandler';
|
|
46
55
|
|
|
47
56
|
// ---------------------------------------------------------------------------
|
|
48
57
|
// Helpers
|
|
@@ -66,11 +75,7 @@ function writePageScript(javascript: string | undefined, scriptsDir: string): st
|
|
|
66
75
|
return [`/_scripts/${scriptFile}`];
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
function copyDirectory(
|
|
70
|
-
src: string,
|
|
71
|
-
dest: string,
|
|
72
|
-
filter?: (filename: string) => boolean,
|
|
73
|
-
): void {
|
|
78
|
+
function copyDirectory(src: string, dest: string, filter?: (filename: string) => boolean): void {
|
|
74
79
|
if (!existsSync(src)) return;
|
|
75
80
|
if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
|
|
76
81
|
const files = readdirSync(src);
|
|
@@ -87,9 +92,7 @@ function copyDirectory(
|
|
|
87
92
|
// Astro's <Picture> re-derives responsive variants from originals at build
|
|
88
93
|
// time, so the pre-baked -{width}.webp/.avif files and the SSR-only
|
|
89
94
|
// manifest.json are dead weight in the exported project.
|
|
90
|
-
const imageVariantSuffixRe = new RegExp(
|
|
91
|
-
`-(${RESPONSIVE_WIDTHS.join('|')})\\.(webp|avif)$`,
|
|
92
|
-
);
|
|
95
|
+
const imageVariantSuffixRe = new RegExp(`-(${RESPONSIVE_WIDTHS.join('|')})\\.(webp|avif)$`);
|
|
93
96
|
function shouldCopyImageForAstro(filename: string): boolean {
|
|
94
97
|
if (filename === 'manifest.json') return false;
|
|
95
98
|
if (imageVariantSuffixRe.test(filename)) return false;
|
|
@@ -108,7 +111,7 @@ function buildCMSItemPath(
|
|
|
108
111
|
item: CMSItem,
|
|
109
112
|
slugField: string,
|
|
110
113
|
locale: string,
|
|
111
|
-
i18nConfig: I18nConfig
|
|
114
|
+
i18nConfig: I18nConfig,
|
|
112
115
|
): string {
|
|
113
116
|
let slug = item[slugField] ?? item._slug ?? item._id;
|
|
114
117
|
if (isI18nValue(slug)) {
|
|
@@ -156,10 +159,7 @@ function escapeTemplateLiteral(s: string): string {
|
|
|
156
159
|
* Compute locale → URL path map for a page's slug translations.
|
|
157
160
|
* Used by locale list rendering to generate correct links.
|
|
158
161
|
*/
|
|
159
|
-
function computePageSlugMap(
|
|
160
|
-
slugs: Record<string, string>,
|
|
161
|
-
i18nConfig: I18nConfig
|
|
162
|
-
): Record<string, string> {
|
|
162
|
+
function computePageSlugMap(slugs: Record<string, string>, i18nConfig: I18nConfig): Record<string, string> {
|
|
163
163
|
const map: Record<string, string> = {};
|
|
164
164
|
for (const localeConfig of i18nConfig.locales) {
|
|
165
165
|
const code = localeConfig.code;
|
|
@@ -182,7 +182,9 @@ function cmsFieldToZod(field: CMSFieldDefinition): string {
|
|
|
182
182
|
case 'string':
|
|
183
183
|
case 'text':
|
|
184
184
|
case 'rich-text':
|
|
185
|
-
//
|
|
185
|
+
// Rich-text is serialized to an HTML string at item-copy time (see the
|
|
186
|
+
// CMS collection emission below), so by the time Astro validates it the
|
|
187
|
+
// value is a string (or an i18n object of strings). Support both.
|
|
186
188
|
return 'z.union([z.string(), z.object({ _i18n: z.literal(true) }).passthrough()])';
|
|
187
189
|
case 'number':
|
|
188
190
|
return 'z.number()';
|
|
@@ -192,7 +194,7 @@ function cmsFieldToZod(field: CMSFieldDefinition): string {
|
|
|
192
194
|
return 'z.coerce.date()';
|
|
193
195
|
case 'select':
|
|
194
196
|
if (field.options && field.options.length > 0) {
|
|
195
|
-
const opts = field.options.map(o => `'${o.replace(/'/g, "\\'")}'`).join(', ');
|
|
197
|
+
const opts = field.options.map((o) => `'${o.replace(/'/g, "\\'")}'`).join(', ');
|
|
196
198
|
return `z.enum([${opts}])`;
|
|
197
199
|
}
|
|
198
200
|
return 'z.string()';
|
|
@@ -206,6 +208,101 @@ function cmsFieldToZod(field: CMSFieldDefinition): string {
|
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Serialize a single rich-text field value to an HTML string. Handles plain
|
|
213
|
+
* Tiptap doc objects, the `{ html: "..." }` marker shape, i18n-wrapped values
|
|
214
|
+
* ({ _i18n: true, en: <doc|string>, ... }), and already-serialized strings.
|
|
215
|
+
*/
|
|
216
|
+
function serializeRichTextValue(value: unknown): unknown {
|
|
217
|
+
const one = (v: unknown): unknown => {
|
|
218
|
+
if (v == null || typeof v === 'string') return v ?? '';
|
|
219
|
+
if (isTiptapDocument(v)) return tiptapToHtml(v);
|
|
220
|
+
if (typeof v === 'object' && v !== null && typeof (v as { html?: unknown }).html === 'string') {
|
|
221
|
+
return (v as { html: string }).html;
|
|
222
|
+
}
|
|
223
|
+
return v;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
if (isI18nValue(value)) {
|
|
227
|
+
const out: Record<string, unknown> = { _i18n: true };
|
|
228
|
+
for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
|
|
229
|
+
if (k === '_i18n') continue;
|
|
230
|
+
out[k] = one(v);
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
return one(value);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Walk a component structure and collect the names of every component instance
|
|
239
|
+
* it references (`{ type: 'component', component: 'X' }`).
|
|
240
|
+
*/
|
|
241
|
+
function collectComponentRefs(node: unknown, acc: Set<string>): void {
|
|
242
|
+
if (Array.isArray(node)) {
|
|
243
|
+
for (const child of node) collectComponentRefs(child, acc);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (!node || typeof node !== 'object') return;
|
|
247
|
+
const n = node as Record<string, unknown>;
|
|
248
|
+
if (n.type === 'component' && typeof n.component === 'string') {
|
|
249
|
+
acc.add(n.component);
|
|
250
|
+
}
|
|
251
|
+
for (const value of Object.values(n)) {
|
|
252
|
+
if (value && typeof value === 'object') collectComponentRefs(value, acc);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Compute the set of components that consume the CMS entry (`{{cms.*}}`),
|
|
258
|
+
* transitively including any component that renders a consumer in its own
|
|
259
|
+
* structure (it must forward the `cms` prop down). Astro components have
|
|
260
|
+
* isolated scopes, so each consumer needs the entry threaded in explicitly.
|
|
261
|
+
*/
|
|
262
|
+
function computeCmsConsumerComponents(components: Record<string, ComponentDefinition>): Set<string> {
|
|
263
|
+
const consumers = new Set<string>();
|
|
264
|
+
const refsByComponent = new Map<string, Set<string>>();
|
|
265
|
+
|
|
266
|
+
for (const [name, def] of Object.entries(components)) {
|
|
267
|
+
const structure = def.component?.structure;
|
|
268
|
+
if (structure && JSON.stringify(structure).includes('{{cms.')) {
|
|
269
|
+
consumers.add(name);
|
|
270
|
+
}
|
|
271
|
+
const refs = new Set<string>();
|
|
272
|
+
collectComponentRefs(structure, refs);
|
|
273
|
+
refsByComponent.set(name, refs);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Fixpoint: a component that renders a consumer is itself a consumer/forwarder.
|
|
277
|
+
let changed = true;
|
|
278
|
+
while (changed) {
|
|
279
|
+
changed = false;
|
|
280
|
+
for (const [name, refs] of refsByComponent) {
|
|
281
|
+
if (consumers.has(name)) continue;
|
|
282
|
+
for (const ref of refs) {
|
|
283
|
+
if (consumers.has(ref)) {
|
|
284
|
+
consumers.add(name);
|
|
285
|
+
changed = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return consumers;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Build the `_url` expression (a JS template literal over the `e` collection
|
|
296
|
+
* entry) for a CMS collection, so flattened list items expose a usable link.
|
|
297
|
+
* E.g. urlPattern "/blog/{{slug}}" + slugField "slug" → `/blog/${e.data.slug ?? e.id}`.
|
|
298
|
+
*/
|
|
299
|
+
function buildCollectionUrlExpr(schema: CMSSchema): string {
|
|
300
|
+
const slugField = schema.slugField || 'slug';
|
|
301
|
+
const pattern = schema.urlPattern || `/${schema.id}/{{slug}}`;
|
|
302
|
+
const body = pattern.replace(/\{\{[^}]+\}\}/, '${e.data.' + slugField + ' ?? e.id}');
|
|
303
|
+
return '`' + body + '`';
|
|
304
|
+
}
|
|
305
|
+
|
|
209
306
|
// ---------------------------------------------------------------------------
|
|
210
307
|
// Types
|
|
211
308
|
// ---------------------------------------------------------------------------
|
|
@@ -260,15 +357,13 @@ function buildSSRFallbackPage(
|
|
|
260
357
|
fontPreloads: string,
|
|
261
358
|
libraryTags: { headCSS?: string; headJS?: string; bodyEndJS?: string },
|
|
262
359
|
defaultTheme: string,
|
|
263
|
-
scriptPaths: string[]
|
|
360
|
+
scriptPaths: string[],
|
|
264
361
|
): string {
|
|
265
362
|
const escapedMeta = escapeTemplateLiteral(result.meta);
|
|
266
363
|
const escapedHTML = escapeTemplateLiteral(result.html);
|
|
267
364
|
const escapedFontPreloads = escapeTemplateLiteral(fontPreloads);
|
|
268
365
|
|
|
269
|
-
const scriptsArrayLiteral = scriptPaths.length > 0
|
|
270
|
-
? `[${scriptPaths.map(s => `"${s}"`).join(', ')}]`
|
|
271
|
-
: '[]';
|
|
366
|
+
const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(', ')}]` : '[]';
|
|
272
367
|
|
|
273
368
|
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral(libraryTags.headCSS || '')}\`, headJS: \`${escapeTemplateLiteral(libraryTags.headJS || '')}\`, bodyEndJS: \`${escapeTemplateLiteral(libraryTags.bodyEndJS || '')}\` }`;
|
|
274
369
|
|
|
@@ -293,10 +388,7 @@ import BaseLayout from '${importPath}';
|
|
|
293
388
|
// Main export
|
|
294
389
|
// ---------------------------------------------------------------------------
|
|
295
390
|
|
|
296
|
-
export async function buildAstroProject(
|
|
297
|
-
projectRoot?: string,
|
|
298
|
-
outputDir?: string
|
|
299
|
-
): Promise<AstroBuildStats> {
|
|
391
|
+
export async function buildAstroProject(projectRoot?: string, outputDir?: string): Promise<AstroBuildStats> {
|
|
300
392
|
// ----------------------------------------------------------
|
|
301
393
|
// 1. Setup: load project configuration
|
|
302
394
|
// ----------------------------------------------------------
|
|
@@ -311,7 +403,9 @@ export async function buildAstroProject(
|
|
|
311
403
|
|
|
312
404
|
const { components, warnings, errors: compErrors } = await loadComponentDirectory(projectPaths.components());
|
|
313
405
|
const globalComponents: Record<string, ComponentDefinition> = {};
|
|
314
|
-
components.forEach((value, key) => {
|
|
406
|
+
components.forEach((value, key) => {
|
|
407
|
+
globalComponents[key] = value;
|
|
408
|
+
});
|
|
315
409
|
for (const w of warnings) console.warn(` Warning: ${w}`);
|
|
316
410
|
for (const e of compErrors) console.error(` Error: ${e}`);
|
|
317
411
|
|
|
@@ -382,7 +476,9 @@ export async function buildAstroProject(
|
|
|
382
476
|
const pageId = basePath === '/' ? 'index' : basePath.substring(1);
|
|
383
477
|
slugMappings.push({ pageId, slugs: pageData.meta.slugs });
|
|
384
478
|
}
|
|
385
|
-
} catch {
|
|
479
|
+
} catch {
|
|
480
|
+
/* ignore parse errors in first pass */
|
|
481
|
+
}
|
|
386
482
|
}
|
|
387
483
|
|
|
388
484
|
// ----------------------------------------------------------
|
|
@@ -406,13 +502,25 @@ export async function buildAstroProject(
|
|
|
406
502
|
|
|
407
503
|
// Helper to process a render result
|
|
408
504
|
function processRenderResult(
|
|
409
|
-
result: {
|
|
505
|
+
result: {
|
|
506
|
+
html: string;
|
|
507
|
+
meta: string;
|
|
508
|
+
title: string;
|
|
509
|
+
javascript: string;
|
|
510
|
+
componentCSS?: string;
|
|
511
|
+
locale: string;
|
|
512
|
+
interactiveStylesMap: Map<string, InteractiveStyles>;
|
|
513
|
+
preloadImages: any[];
|
|
514
|
+
neededCollections: Set<string>;
|
|
515
|
+
ssrFallbackCollector?: Map<string, string>;
|
|
516
|
+
processedRawHtmlCollector?: Map<string, string>;
|
|
517
|
+
},
|
|
410
518
|
urlPath: string,
|
|
411
519
|
astroFilePath: string,
|
|
412
520
|
fileDepth: number,
|
|
413
521
|
pageData?: JSONPage,
|
|
414
522
|
pageName?: string,
|
|
415
|
-
isCMSPage?: boolean
|
|
523
|
+
isCMSPage?: boolean,
|
|
416
524
|
): void {
|
|
417
525
|
// Collect interactive styles
|
|
418
526
|
mergeInteractiveStyles(result.interactiveStylesMap);
|
|
@@ -484,7 +592,12 @@ export async function buildAstroProject(
|
|
|
484
592
|
// Compute URL path
|
|
485
593
|
let slug: string;
|
|
486
594
|
if (slugs && slugs[locale]) {
|
|
487
|
-
|
|
595
|
+
// Slugs may be authored with a leading slash (e.g. "/blog" from the
|
|
596
|
+
// page-rename flow). Normalize to the bare form the rest of the
|
|
597
|
+
// pipeline expects — matches buildPageUrlForLocale(). A leading slash
|
|
598
|
+
// here would otherwise inflate fileDepth (".../blog.astro".split('/'))
|
|
599
|
+
// and produce a wrong "../../layouts" import.
|
|
600
|
+
slug = slugs[locale].replace(/^\/+/, '');
|
|
488
601
|
} else if (basePath === '/') {
|
|
489
602
|
slug = '';
|
|
490
603
|
} else {
|
|
@@ -492,8 +605,12 @@ export async function buildAstroProject(
|
|
|
492
605
|
}
|
|
493
606
|
|
|
494
607
|
const urlPath = isDefault
|
|
495
|
-
?
|
|
496
|
-
|
|
608
|
+
? slug === ''
|
|
609
|
+
? '/'
|
|
610
|
+
: `/${slug}`
|
|
611
|
+
: slug === ''
|
|
612
|
+
? `/${locale}`
|
|
613
|
+
: `/${locale}/${slug}`;
|
|
497
614
|
|
|
498
615
|
// Determine .astro file path relative to src/pages/
|
|
499
616
|
const astroFileName = slug === '' ? 'index.astro' : `${slug}.astro`;
|
|
@@ -510,7 +627,7 @@ export async function buildAstroProject(
|
|
|
510
627
|
slugMappings,
|
|
511
628
|
undefined, // cmsContext
|
|
512
629
|
cmsService,
|
|
513
|
-
true // isProductionBuild
|
|
630
|
+
true, // isProductionBuild
|
|
514
631
|
);
|
|
515
632
|
|
|
516
633
|
processRenderResult(result, urlPath, astroFilePath, fileDepth, pageData, pageName, false);
|
|
@@ -584,8 +701,34 @@ export async function buildAstroProject(
|
|
|
584
701
|
const templateSchemas: CMSSchema[] = [];
|
|
585
702
|
let cmsPageCount = 0;
|
|
586
703
|
|
|
704
|
+
// Pre-pass: components that consume the CMS entry (so the page/component
|
|
705
|
+
// emitters know which instances to thread `cms={...}` into), plus per-
|
|
706
|
+
// collection `_url` expressions (for flattened collection lists). Built
|
|
707
|
+
// before the template loop so the very first emitted CMS page sees the
|
|
708
|
+
// full picture even when it lists items from another collection.
|
|
709
|
+
const cmsConsumerComponents = computeCmsConsumerComponents(globalComponents);
|
|
710
|
+
const collectionUrlExpr = new Map<string, string>();
|
|
711
|
+
const mergedRichTextFields = new Set<string>();
|
|
712
|
+
if (existsSync(templatesDir)) {
|
|
713
|
+
for (const file of readdirSync(templatesDir).filter((f) => f.endsWith('.json'))) {
|
|
714
|
+
const tc = await loadJSONFile(join(templatesDir, file));
|
|
715
|
+
if (!tc) continue;
|
|
716
|
+
try {
|
|
717
|
+
const pd = parseJSON<JSONPage>(tc);
|
|
718
|
+
const schema = pd.meta?.cms as CMSSchema | undefined;
|
|
719
|
+
if (!schema?.id) continue;
|
|
720
|
+
collectionUrlExpr.set(schema.id, buildCollectionUrlExpr(schema));
|
|
721
|
+
for (const [fn, fd] of Object.entries(schema.fields || {})) {
|
|
722
|
+
if (fd.type === 'rich-text') mergedRichTextFields.add(fn);
|
|
723
|
+
}
|
|
724
|
+
} catch {
|
|
725
|
+
/* ignore parse errors; handled in main loop */
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
587
730
|
if (existsSync(templatesDir)) {
|
|
588
|
-
const templateFiles = readdirSync(templatesDir).filter(f => f.endsWith('.json'));
|
|
731
|
+
const templateFiles = readdirSync(templatesDir).filter((f) => f.endsWith('.json'));
|
|
589
732
|
|
|
590
733
|
for (const file of templateFiles) {
|
|
591
734
|
const templateContent = await loadJSONFile(join(templatesDir, file));
|
|
@@ -613,7 +756,7 @@ export async function buildAstroProject(
|
|
|
613
756
|
|
|
614
757
|
// Render SSR once for metadata collection (interactive styles, component CSS, JS)
|
|
615
758
|
const defaultLocale = i18nConfig.defaultLocale;
|
|
616
|
-
const dummyPath = cmsSchema.urlPattern.replace('{{slug}}',
|
|
759
|
+
const dummyPath = cmsSchema.urlPattern.replace('{{slug}}', CMS_SLUG_PLACEHOLDER);
|
|
617
760
|
|
|
618
761
|
const metaResult = await renderPageSSR(
|
|
619
762
|
pageData,
|
|
@@ -625,7 +768,7 @@ export async function buildAstroProject(
|
|
|
625
768
|
slugMappings,
|
|
626
769
|
undefined, // no CMS context - just collecting metadata
|
|
627
770
|
cmsService,
|
|
628
|
-
true
|
|
771
|
+
true,
|
|
629
772
|
);
|
|
630
773
|
|
|
631
774
|
// Collect interactive styles and component CSS
|
|
@@ -663,13 +806,9 @@ export async function buildAstroProject(
|
|
|
663
806
|
// Route file path: blog/[slug].astro for default, pl/blog/[slug].astro for non-default
|
|
664
807
|
let astroFilePath: string;
|
|
665
808
|
if (pathPrefix) {
|
|
666
|
-
astroFilePath = isDefault
|
|
667
|
-
? `${pathPrefix}[slug].astro`
|
|
668
|
-
: `${localeCode}/${pathPrefix}[slug].astro`;
|
|
809
|
+
astroFilePath = isDefault ? `${pathPrefix}[slug].astro` : `${localeCode}/${pathPrefix}[slug].astro`;
|
|
669
810
|
} else {
|
|
670
|
-
astroFilePath = isDefault
|
|
671
|
-
? '[slug].astro'
|
|
672
|
-
: `${localeCode}/[slug].astro`;
|
|
811
|
+
astroFilePath = isDefault ? '[slug].astro' : `${localeCode}/[slug].astro`;
|
|
673
812
|
}
|
|
674
813
|
|
|
675
814
|
const fileDepth = astroFilePath.split('/').length - 1;
|
|
@@ -699,6 +838,8 @@ export async function buildAstroProject(
|
|
|
699
838
|
imageFormat: configService.getImageFormat(),
|
|
700
839
|
processedRawHtml: metaResult.processedRawHtmlCollector,
|
|
701
840
|
remConfig: remConversionConfig,
|
|
841
|
+
cmsConsumers: cmsConsumerComponents,
|
|
842
|
+
collectionUrlExpr,
|
|
702
843
|
});
|
|
703
844
|
|
|
704
845
|
const astroFileFull = join(pagesOutDir, astroFilePath);
|
|
@@ -740,9 +881,7 @@ export async function buildAstroProject(
|
|
|
740
881
|
}`;
|
|
741
882
|
|
|
742
883
|
const safelistClasses = Array.from(mappingClasses);
|
|
743
|
-
const safelistDirectives = safelistClasses
|
|
744
|
-
.map(c => `@source inline("${c}");`)
|
|
745
|
-
.join('\n');
|
|
884
|
+
const safelistDirectives = safelistClasses.map((c) => `@source inline("${c}");`).join('\n');
|
|
746
885
|
const tailwindDirectives = safelistDirectives
|
|
747
886
|
? `@import "tailwindcss";\n\n${safelistDirectives}`
|
|
748
887
|
: `@import "tailwindcss";`;
|
|
@@ -758,19 +897,14 @@ export async function buildAstroProject(
|
|
|
758
897
|
// ----------------------------------------------------------
|
|
759
898
|
// Escape for embedding inside Astro <Fragment set:html={`...`}> template
|
|
760
899
|
// literals in the generated BaseLayout file.
|
|
761
|
-
const escForTemplateLiteral = (s: string) => s
|
|
762
|
-
.replace(/\\/g, '\\\\')
|
|
763
|
-
.replace(/`/g, '\\`')
|
|
764
|
-
.replace(/\$\{/g, '\\${');
|
|
900
|
+
const escForTemplateLiteral = (s: string) => s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
765
901
|
|
|
766
902
|
const customHeadLiteral = escForTemplateLiteral(customCode.head || '');
|
|
767
903
|
const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || '');
|
|
768
904
|
const customBodyEndLiteral = escForTemplateLiteral(customCode.bodyEnd || '');
|
|
769
905
|
const iconTagsLiteral = escForTemplateLiteral(iconTagsHtml);
|
|
770
906
|
|
|
771
|
-
const formHandlerBlock = projectNeedsFormHandler
|
|
772
|
-
? `\n <script is:inline>\n${formHandlerScript}\n </script>`
|
|
773
|
-
: '';
|
|
907
|
+
const formHandlerBlock = projectNeedsFormHandler ? `\n <script is:inline>\n${formHandlerScript}\n </script>` : '';
|
|
774
908
|
|
|
775
909
|
const baseLayoutContent = `---
|
|
776
910
|
import '../styles/global.css';
|
|
@@ -815,10 +949,29 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
815
949
|
// ----------------------------------------------------------
|
|
816
950
|
// 7.5. Generate component .astro files
|
|
817
951
|
// ----------------------------------------------------------
|
|
952
|
+
// SSR/Next.js resolve orphan `{{x}}` refs in a component's structure via
|
|
953
|
+
// the parentProps cascade in templateEngine. Astro can't fall back at
|
|
954
|
+
// runtime (each .astro file is its own scope), so we lift orphan refs
|
|
955
|
+
// onto each component's interface and forward them from hosts that
|
|
956
|
+
// declare the same prop. See `normalizeOrphanTemplateProps` for details.
|
|
957
|
+
const emittableComponents = normalizeOrphanTemplateProps(globalComponents);
|
|
818
958
|
let componentFileCount = 0;
|
|
819
|
-
for (const [compName, compDef] of Object.entries(
|
|
959
|
+
for (const [compName, compDef] of Object.entries(emittableComponents)) {
|
|
820
960
|
try {
|
|
821
|
-
const astroContent = emitAstroComponent(
|
|
961
|
+
const astroContent = emitAstroComponent(
|
|
962
|
+
compName,
|
|
963
|
+
compDef,
|
|
964
|
+
emittableComponents,
|
|
965
|
+
breakpoints,
|
|
966
|
+
i18nConfig.defaultLocale,
|
|
967
|
+
responsiveScales,
|
|
968
|
+
remConversionConfig,
|
|
969
|
+
{
|
|
970
|
+
cmsConsumers: cmsConsumerComponents,
|
|
971
|
+
cmsRichTextFields: mergedRichTextFields,
|
|
972
|
+
collectionUrlExpr,
|
|
973
|
+
},
|
|
974
|
+
);
|
|
822
975
|
await writeFile(join(componentsOutDir, `${compName}.astro`), astroContent, 'utf-8');
|
|
823
976
|
componentFileCount++;
|
|
824
977
|
} catch (error: any) {
|
|
@@ -843,16 +996,15 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
843
996
|
const ssrFallbacks = result.ssrFallbackCollector ?? new Map<string, string>();
|
|
844
997
|
|
|
845
998
|
// Compute slug map for locale list rendering
|
|
846
|
-
const pageSlugMap: Record<string, string> | undefined =
|
|
847
|
-
result.pageData.meta
|
|
848
|
-
|
|
849
|
-
: undefined;
|
|
999
|
+
const pageSlugMap: Record<string, string> | undefined = result.pageData.meta?.slugs
|
|
1000
|
+
? computePageSlugMap(result.pageData.meta.slugs, i18nConfig)
|
|
1001
|
+
: undefined;
|
|
850
1002
|
|
|
851
1003
|
// Component-structured pages don't need page-level _scripts/*.js
|
|
852
1004
|
// because each .astro component already has its own inline <script>
|
|
853
1005
|
astroContent = emitAstroPage({
|
|
854
1006
|
pageData: result.pageData,
|
|
855
|
-
globalComponents,
|
|
1007
|
+
globalComponents: emittableComponents,
|
|
856
1008
|
title: result.title,
|
|
857
1009
|
meta: result.meta,
|
|
858
1010
|
locale: result.locale,
|
|
@@ -876,7 +1028,9 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
876
1028
|
});
|
|
877
1029
|
} catch (error: any) {
|
|
878
1030
|
// Fallback to SSR HTML if component emission fails — needs page-level script
|
|
879
|
-
console.warn(
|
|
1031
|
+
console.warn(
|
|
1032
|
+
` Warning: component emission failed for ${result.urlPath}, using SSR fallback: ${error?.message}`,
|
|
1033
|
+
);
|
|
880
1034
|
scriptPaths = writePageScript(result.javascript, scriptsDir);
|
|
881
1035
|
astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
|
|
882
1036
|
}
|
|
@@ -931,10 +1085,22 @@ export const GET: APIRoute = () => {
|
|
|
931
1085
|
const collectionDir = join(contentDir, schema.id);
|
|
932
1086
|
mkdirSync(collectionDir, { recursive: true });
|
|
933
1087
|
|
|
1088
|
+
// Rich-text fields are stored as Tiptap doc objects; Astro's content
|
|
1089
|
+
// schema (and `<Fragment set:html>`) expects HTML strings. Mirror the
|
|
1090
|
+
// live SSR (cmsSSRProcessor) by serializing them to HTML at copy time.
|
|
1091
|
+
const richTextFieldNames = Object.entries(schema.fields || {})
|
|
1092
|
+
.filter(([, fd]) => fd.type === 'rich-text')
|
|
1093
|
+
.map(([fn]) => fn);
|
|
1094
|
+
|
|
934
1095
|
// Copy CMS item JSON files, resolving i18n values to default locale
|
|
935
1096
|
const cmsItemsDir = join(projectPaths.cms(), schema.id);
|
|
936
1097
|
if (existsSync(cmsItemsDir)) {
|
|
937
|
-
|
|
1098
|
+
// Skip `*.draft.json` siblings in production builds — they mirror the
|
|
1099
|
+
// published item-list filter and may hold partial/invalid WIP data.
|
|
1100
|
+
const isDevBuild = process.env.MENO_DEV_BUILD === 'true';
|
|
1101
|
+
const itemFiles = readdirSync(cmsItemsDir).filter(
|
|
1102
|
+
(f) => f.endsWith('.json') && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`)),
|
|
1103
|
+
);
|
|
938
1104
|
|
|
939
1105
|
for (const itemFile of itemFiles) {
|
|
940
1106
|
try {
|
|
@@ -944,11 +1110,13 @@ export const GET: APIRoute = () => {
|
|
|
944
1110
|
// Keep i18n values as-is so getStaticPaths() can resolve per-locale
|
|
945
1111
|
const resolved: Record<string, unknown> = { ...item };
|
|
946
1112
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1113
|
+
// Serialize rich-text fields (Tiptap doc → HTML string), handling
|
|
1114
|
+
// i18n-wrapped values ({ _i18n: true, en: <doc>, ... }) per-locale.
|
|
1115
|
+
for (const fieldName of richTextFieldNames) {
|
|
1116
|
+
resolved[fieldName] = serializeRichTextValue(resolved[fieldName]);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
await writeFile(join(collectionDir, itemFile), JSON.stringify(resolved, null, 2), 'utf-8');
|
|
952
1120
|
} catch (err: any) {
|
|
953
1121
|
console.warn(` Warning: could not process CMS item ${itemFile}: ${err?.message}`);
|
|
954
1122
|
}
|
|
@@ -1015,7 +1183,7 @@ export { collections };
|
|
|
1015
1183
|
const srcAssetDir = join(projectPaths.project, dir);
|
|
1016
1184
|
if (existsSync(srcAssetDir)) {
|
|
1017
1185
|
copyDirectory(srcAssetDir, join(publicDir, dir));
|
|
1018
|
-
|
|
1186
|
+
}
|
|
1019
1187
|
}
|
|
1020
1188
|
|
|
1021
1189
|
// Copy libraries folder if it exists
|
|
@@ -1052,24 +1220,23 @@ export { collections };
|
|
|
1052
1220
|
preview: 'astro preview',
|
|
1053
1221
|
},
|
|
1054
1222
|
dependencies: {
|
|
1055
|
-
|
|
1223
|
+
// Astro 5 (stable Vite), NOT 6 — Astro 6's rolldown-vite breaks
|
|
1224
|
+
// @tailwindcss/vite at build time ("Missing field `tsconfigPaths`").
|
|
1225
|
+
astro: '^5.0.0',
|
|
1056
1226
|
'@astrojs/sitemap': '^3.0.0',
|
|
1057
1227
|
'@tailwindcss/vite': '^4.0.0',
|
|
1058
|
-
|
|
1059
|
-
},
|
|
1060
|
-
// Astro 6 expects Vite 7; pin it so npm doesn't pull Vite 8+ and warn.
|
|
1061
|
-
overrides: {
|
|
1062
|
-
'vite': '^7.0.0',
|
|
1228
|
+
tailwindcss: '^4.0.0',
|
|
1063
1229
|
},
|
|
1064
1230
|
};
|
|
1065
1231
|
|
|
1066
1232
|
await writeFile(join(outDir, 'package.json'), JSON.stringify(packageJson, null, 2), 'utf-8');
|
|
1067
1233
|
|
|
1068
1234
|
// astro.config.mjs
|
|
1069
|
-
const localeCodes = i18nConfig.locales.map(l => l.code);
|
|
1070
|
-
const i18nBlock =
|
|
1071
|
-
|
|
1072
|
-
: ''
|
|
1235
|
+
const localeCodes = i18nConfig.locales.map((l) => l.code);
|
|
1236
|
+
const i18nBlock =
|
|
1237
|
+
i18nConfig.locales.length > 1
|
|
1238
|
+
? `\n i18n: {\n defaultLocale: '${i18nConfig.defaultLocale}',\n locales: [${localeCodes.map((c) => `'${c}'`).join(', ')}],\n routing: { prefixDefaultLocale: false },\n },`
|
|
1239
|
+
: '';
|
|
1073
1240
|
|
|
1074
1241
|
const astroConfig = `import { defineConfig } from 'astro/config';
|
|
1075
1242
|
import tailwindcss from '@tailwindcss/vite';
|
|
@@ -1092,6 +1259,27 @@ export default defineConfig({${siteUrl ? `\n site: '${siteUrl}',` : ''}${i18nBl
|
|
|
1092
1259
|
|
|
1093
1260
|
await writeFile(join(outDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2), 'utf-8');
|
|
1094
1261
|
|
|
1262
|
+
// netlify.toml — makes the exported project deployable on Netlify out of the
|
|
1263
|
+
// box. `astro` is a real dependency here (see package.json above), so once
|
|
1264
|
+
// Netlify runs `npm install`, `astro build` is on PATH and writes to dist/.
|
|
1265
|
+
// Harmless on other hosts (Cloudflare Pages / Vercel ignore this file).
|
|
1266
|
+
//
|
|
1267
|
+
// Multi-locale projects WITH a 404 page (pages/404.json) also get the managed
|
|
1268
|
+
// locale-404 redirects block (lib/shared/netlifyLocale404.ts): the regular-pages
|
|
1269
|
+
// loop above emits src/pages/<locale>/404.astro per non-default locale, which
|
|
1270
|
+
// Astro builds to dist/<locale>/404/index.html — exactly the rules' rewrite
|
|
1271
|
+
// target — while the root 404.astro becomes Netlify's default catch-all 404.html.
|
|
1272
|
+
const baseNetlifyToml = `# Generated by Meno's Astro build.
|
|
1273
|
+
[build]
|
|
1274
|
+
command = "npm run build"
|
|
1275
|
+
publish = "dist"
|
|
1276
|
+
|
|
1277
|
+
[build.environment]
|
|
1278
|
+
NODE_VERSION = "22"
|
|
1279
|
+
`;
|
|
1280
|
+
const netlifyToml = syncNetlifyLocale404Block(baseNetlifyToml, i18nConfig, pageFiles.includes('404.json'));
|
|
1281
|
+
await writeFile(join(outDir, 'netlify.toml'), netlifyToml, 'utf-8');
|
|
1282
|
+
|
|
1095
1283
|
// src/env.d.ts — resolves astro:assets and other virtual module types in IDE
|
|
1096
1284
|
await writeFile(join(outDir, 'src', 'env.d.ts'), '/// <reference path="../.astro/types.d.ts" />\n', 'utf-8');
|
|
1097
1285
|
|