meno-core 1.0.53 → 1.1.0
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 +66 -261
- package/build-astro.ts +150 -128
- package/dist/bin/cli.js +42 -185
- package/dist/bin/cli.js.map +2 -2
- package/dist/chunks/chunk-2AR55GYH.js +42 -0
- package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
- package/dist/chunks/{chunk-JGWFTO6P.js → chunk-2IIQK7T3.js} +2624 -1389
- package/dist/chunks/chunk-2IIQK7T3.js.map +7 -0
- package/dist/chunks/chunk-4ZRU52J2.js +169 -0
- package/dist/chunks/chunk-4ZRU52J2.js.map +7 -0
- package/dist/chunks/{chunk-UB44F4Z2.js → chunk-5X4HCN7J.js} +5 -7
- package/dist/chunks/chunk-5X4HCN7J.js.map +7 -0
- package/dist/chunks/{chunk-WQFG7PAH.js → chunk-7CCVOL5M.js} +15 -19
- package/dist/chunks/chunk-7CCVOL5M.js.map +7 -0
- package/dist/chunks/{chunk-YBLHKYFF.js → chunk-AR7LHIFY.js} +8 -2
- package/dist/chunks/chunk-AR7LHIFY.js.map +7 -0
- package/dist/chunks/{chunk-O3NAGJP4.js → chunk-NUP7H7D3.js} +135 -41
- package/dist/chunks/chunk-NUP7H7D3.js.map +7 -0
- package/dist/chunks/{chunk-X754AHS5.js → chunk-QWTQZHG3.js} +194 -90
- package/dist/chunks/chunk-QWTQZHG3.js.map +7 -0
- package/dist/chunks/{chunk-H3GJ4H2U.js → chunk-XTKNX4FW.js} +216 -87
- package/dist/chunks/chunk-XTKNX4FW.js.map +7 -0
- package/dist/chunks/{fs-JGINUXGL.js → fs-G3ANWEFP.js} +2 -2
- package/dist/lib/client/index.js +1003 -475
- package/dist/lib/client/index.js.map +3 -3
- package/dist/lib/server/index.js +14393 -6371
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +342 -101
- 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 +64 -80
- package/dist/lib/test-utils/index.js.map +2 -2
- package/entries/client-router.tsx +10 -8
- package/lib/client/ClientInitializer.ts +8 -8
- package/lib/client/ErrorBoundary.test.tsx +246 -186
- package/lib/client/ErrorBoundary.tsx +183 -132
- package/lib/client/componentRegistry.test.ts +96 -108
- package/lib/client/componentRegistry.ts +1 -3
- package/lib/client/contexts/ThemeContext.tsx +3 -2
- package/lib/client/core/ComponentBuilder.test.ts +663 -560
- package/lib/client/core/ComponentBuilder.ts +427 -155
- package/lib/client/core/ComponentRenderer.test.tsx +2 -4
- package/lib/client/core/ComponentRenderer.tsx +46 -33
- package/lib/client/core/builders/embedBuilder.ts +242 -54
- package/lib/client/core/builders/linkBuilder.ts +72 -45
- package/lib/client/core/builders/linkNodeBuilder.ts +79 -54
- package/lib/client/core/builders/listBuilder.ts +155 -89
- package/lib/client/core/builders/localeListBuilder.ts +97 -62
- package/lib/client/core/builders/types.ts +5 -5
- package/lib/client/core/cmsTemplateProcessor.ts +8 -9
- package/lib/client/elementRegistry.ts +3 -3
- package/lib/client/fontFamiliesService.test.ts +2 -10
- package/lib/client/fontFamiliesService.ts +3 -3
- package/lib/client/hmr/HMRManager.tsx +47 -30
- package/lib/client/hmrCssReload.ts +49 -14
- package/lib/client/hmrWebSocket.ts +14 -19
- package/lib/client/hooks/useColorVariables.test.ts +21 -21
- package/lib/client/hooks/useColorVariables.ts +23 -18
- package/lib/client/hooks/usePropertyAutocomplete.ts +4 -6
- package/lib/client/hooks/useVariables.ts +6 -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/meno-filter/MenoFilter.test.ts +47 -49
- package/lib/client/meno-filter/MenoFilter.ts +14 -15
- package/lib/client/meno-filter/bindings.ts +18 -43
- package/lib/client/meno-filter/init.ts +4 -4
- package/lib/client/meno-filter/renderer.ts +30 -32
- package/lib/client/meno-filter/script.generated.ts +1 -3
- package/lib/client/meno-filter/ui.ts +4 -6
- package/lib/client/meno-filter/updates.ts +18 -23
- package/lib/client/meno-filter/utils.ts +1 -1
- package/lib/client/navigation.test.ts +174 -178
- package/lib/client/navigation.ts +0 -1
- package/lib/client/responsiveStyleResolver.knownTokens.test.ts +71 -0
- package/lib/client/responsiveStyleResolver.test.ts +234 -232
- package/lib/client/responsiveStyleResolver.ts +74 -20
- package/lib/client/routing/RouteLoader.test.ts +24 -25
- package/lib/client/routing/RouteLoader.ts +27 -35
- package/lib/client/routing/Router.tsx +210 -153
- package/lib/client/scripts/ScriptExecutor.test.ts +157 -158
- package/lib/client/scripts/ScriptExecutor.ts +18 -36
- package/lib/client/services/PrefetchService.test.ts +3 -3
- package/lib/client/services/PrefetchService.ts +23 -29
- package/lib/client/styleProcessor.test.ts +9 -9
- package/lib/client/styleProcessor.ts +24 -15
- package/lib/client/styles/StyleInjector.test.ts +122 -115
- package/lib/client/styles/StyleInjector.ts +10 -7
- package/lib/client/styles/UtilityClassCollector.ts +62 -28
- package/lib/client/styles/cspNonce.test.ts +2 -5
- package/lib/client/templateEngine.test.ts +554 -488
- package/lib/client/templateEngine.ts +203 -73
- package/lib/client/theme.test.ts +1 -1
- 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 +4 -5
- package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
- package/lib/server/__integration__/static-assets.test.ts +3 -3
- package/lib/server/__integration__/test-helpers.ts +87 -74
- package/lib/server/ab/generateFunctions.ts +12 -10
- package/lib/server/astro/cmsPageEmitter.ts +26 -42
- package/lib/server/astro/componentEmitter.ts +35 -43
- package/lib/server/astro/cssCollector.ts +10 -26
- package/lib/server/astro/nodeToAstro.test.ts +1754 -34
- package/lib/server/astro/nodeToAstro.ts +232 -216
- package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +115 -119
- package/lib/server/astro/normalizeOrphanTemplateProps.ts +11 -18
- 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 +17 -20
- package/lib/server/createServer.ts +7 -19
- package/lib/server/cssGenerator.test.ts +35 -44
- package/lib/server/cssGenerator.ts +8 -19
- package/lib/server/fileWatcher.test.ts +164 -13
- package/lib/server/fileWatcher.ts +209 -124
- package/lib/server/index.ts +14 -17
- package/lib/server/jsonLoader.test.ts +39 -2
- package/lib/server/jsonLoader.ts +39 -34
- package/lib/server/middleware/cors.test.ts +21 -21
- package/lib/server/middleware/cors.ts +28 -4
- package/lib/server/middleware/errorHandler.test.ts +7 -5
- package/lib/server/middleware/errorHandler.ts +3 -8
- package/lib/server/middleware/index.ts +0 -1
- package/lib/server/middleware/logger.test.ts +10 -8
- package/lib/server/middleware/logger.ts +17 -29
- package/lib/server/migrateTemplates.ts +3 -3
- package/lib/server/pageCache.test.ts +76 -77
- package/lib/server/pageCache.ts +0 -1
- package/lib/server/projectContext.ts +5 -4
- package/lib/server/providers/fileSystemCMSProvider.test.ts +142 -99
- package/lib/server/providers/fileSystemCMSProvider.ts +62 -38
- package/lib/server/routes/api/cms.test.ts +26 -14
- package/lib/server/routes/api/cms.ts +9 -14
- package/lib/server/routes/api/colors.test.ts +2 -2
- package/lib/server/routes/api/components.ts +31 -35
- package/lib/server/routes/api/config.ts +3 -4
- package/lib/server/routes/api/core-routes.ts +49 -76
- package/lib/server/routes/api/enums.test.ts +2 -2
- package/lib/server/routes/api/functions.ts +9 -17
- package/lib/server/routes/api/index.ts +3 -6
- package/lib/server/routes/api/pages.ts +8 -11
- package/lib/server/routes/api/shared.test.ts +1 -1
- package/lib/server/routes/api/shared.ts +12 -9
- package/lib/server/routes/api/variables.test.ts +3 -5
- package/lib/server/routes/api/variables.ts +1 -1
- package/lib/server/routes/index.ts +25 -28
- package/lib/server/routes/pages.ts +35 -31
- package/lib/server/routes/static.ts +17 -6
- package/lib/server/runtime/bundler.ts +98 -61
- package/lib/server/runtime/fs.ts +16 -26
- package/lib/server/runtime/httpServer.ts +8 -12
- package/lib/server/services/ColorService.test.ts +3 -3
- package/lib/server/services/ColorService.ts +37 -29
- package/lib/server/services/EnumService.test.ts +4 -8
- package/lib/server/services/EnumService.ts +11 -3
- package/lib/server/services/VariableService.test.ts +8 -12
- package/lib/server/services/VariableService.ts +11 -3
- package/lib/server/services/cmsService.test.ts +158 -120
- package/lib/server/services/cmsService.ts +36 -146
- package/lib/server/services/componentService.test.ts +125 -45
- package/lib/server/services/componentService.ts +70 -46
- package/lib/server/services/configService.test.ts +22 -45
- package/lib/server/services/configService.ts +50 -27
- package/lib/server/services/fileWatcherService.ts +42 -8
- package/lib/server/services/index.ts +0 -1
- package/lib/server/services/pageService.test.ts +8 -10
- package/lib/server/services/pageService.ts +32 -18
- package/lib/server/ssr/attributeBuilder.ts +18 -8
- package/lib/server/ssr/buildErrorOverlay.ts +11 -12
- package/lib/server/ssr/clientDataInjector.ts +7 -21
- package/lib/server/ssr/cmsSSRProcessor.ts +4 -8
- package/lib/server/ssr/cssCollector.ts +1 -1
- package/lib/server/ssr/errorOverlay.test.ts +1 -1
- package/lib/server/ssr/errorOverlay.ts +3 -9
- package/lib/server/ssr/htmlGenerator.nonce.test.ts +9 -14
- package/lib/server/ssr/htmlGenerator.test.ts +120 -44
- package/lib/server/ssr/htmlGenerator.ts +126 -91
- package/lib/server/ssr/imageMetadata.test.ts +3 -1
- package/lib/server/ssr/imageMetadata.ts +27 -21
- package/lib/server/ssr/jsCollector.test.ts +8 -18
- package/lib/server/ssr/jsCollector.ts +3 -8
- package/lib/server/ssr/liveReloadIntegration.test.ts +76 -36
- 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 +316 -256
- package/lib/server/ssr/ssrRenderer.ts +795 -243
- package/lib/server/ssrRenderer.test.ts +1048 -954
- package/lib/server/utils/jsonLineMapper.test.ts +28 -28
- package/lib/server/utils/jsonLineMapper.ts +7 -7
- package/lib/server/validateStyleCoverage.ts +18 -21
- package/lib/server/websocketManager.ts +28 -19
- package/lib/shared/attributeNodeUtils.test.ts +15 -15
- package/lib/shared/attributeNodeUtils.ts +5 -12
- package/lib/shared/breakpoints.test.ts +5 -5
- package/lib/shared/breakpoints.ts +4 -11
- package/lib/shared/cmsQuery.test.ts +81 -0
- package/lib/shared/cmsQuery.ts +92 -0
- package/lib/shared/cmsQueryParser.test.ts +50 -42
- package/lib/shared/cmsQueryParser.ts +60 -38
- package/lib/shared/colorConversions.ts +9 -9
- package/lib/shared/colorVariableUtils.test.ts +27 -5
- package/lib/shared/colorVariableUtils.ts +21 -12
- package/lib/shared/componentRefs.ts +1 -5
- package/lib/shared/constants.test.ts +3 -3
- package/lib/shared/constants.ts +8 -8
- package/lib/shared/cssGeneration.test.ts +285 -144
- package/lib/shared/cssGeneration.ts +217 -531
- package/lib/shared/cssNamedColors.ts +152 -30
- package/lib/shared/cssProperties.test.ts +69 -70
- package/lib/shared/cssProperties.ts +298 -114
- package/lib/shared/elementClassName.test.ts +109 -109
- package/lib/shared/elementClassName.ts +3 -3
- package/lib/shared/elementUtils.ts +12 -16
- package/lib/shared/errorLogger.test.ts +12 -12
- 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 +145 -0
- package/lib/shared/expressionEvaluator.ts +52 -24
- package/lib/shared/fontLoader.test.ts +32 -18
- package/lib/shared/fontLoader.ts +2 -2
- package/lib/shared/friendlyError.ts +2 -3
- package/lib/shared/gradientUtils.test.ts +3 -7
- package/lib/shared/gradientUtils.ts +17 -14
- package/lib/shared/hrefRefs.test.ts +2 -2
- package/lib/shared/hrefRefs.ts +2 -10
- package/lib/shared/i18n.test.ts +4 -4
- package/lib/shared/i18n.ts +18 -38
- package/lib/shared/index.ts +27 -0
- package/lib/shared/inlineSvgStyleRules.ts +14 -13
- package/lib/shared/interactiveStyleMappings.test.ts +32 -54
- package/lib/shared/interactiveStyleMappings.ts +11 -24
- package/lib/shared/interactiveStyles.test.ts +165 -188
- package/lib/shared/interfaces/contentProvider.ts +1 -1
- package/lib/shared/itemTemplateUtils.test.ts +11 -17
- package/lib/shared/itemTemplateUtils.ts +27 -39
- package/lib/shared/jsonRepair.ts +16 -10
- package/lib/shared/libraryLoader.test.ts +21 -55
- package/lib/shared/libraryLoader.ts +7 -22
- package/lib/shared/linkUtils.ts +1 -1
- package/lib/shared/logger.test.ts +66 -0
- package/lib/shared/logger.ts +94 -0
- package/lib/shared/markdown.ts +25 -0
- package/lib/shared/netlifyLocale404.test.ts +179 -0
- package/lib/shared/netlifyLocale404.ts +110 -0
- package/lib/shared/nodeUtils.test.ts +28 -16
- package/lib/shared/nodeUtils.ts +76 -23
- package/lib/shared/pathArrayUtils.test.ts +1 -2
- package/lib/shared/pathArrayUtils.ts +1 -1
- package/lib/shared/pathSecurity.ts +2 -2
- package/lib/shared/pathUtils.test.ts +4 -6
- package/lib/shared/pathUtils.ts +42 -49
- 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 +17 -20
- package/lib/shared/paths/PathUtils.ts +13 -13
- package/lib/shared/paths/PathValidator.test.ts +2 -15
- package/lib/shared/paths/PathValidator.ts +12 -10
- package/lib/shared/paths/index.ts +1 -2
- package/lib/shared/permissions.test.ts +168 -0
- package/lib/shared/permissions.ts +162 -0
- package/lib/shared/propResolver.test.ts +240 -244
- package/lib/shared/propResolver.ts +15 -26
- package/lib/shared/pxToRem.test.ts +7 -6
- package/lib/shared/pxToRem.ts +2 -5
- package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +12 -6
- package/lib/shared/registry/ClientRegistry.ts +0 -2
- package/lib/shared/registry/ComponentRegistry.test.ts +46 -32
- package/lib/shared/registry/ComponentRegistry.ts +12 -9
- package/lib/shared/registry/NodeTypeDefinition.ts +16 -9
- package/lib/shared/registry/RegistryManager.ts +1 -2
- package/lib/shared/registry/SSRRegistry.ts +0 -2
- package/lib/shared/registry/createNodeType.ts +7 -9
- package/lib/shared/registry/defineNodeType.ts +2 -6
- package/lib/shared/registry/fieldPresets.ts +3 -1
- package/lib/shared/registry/index.ts +0 -1
- package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
- package/lib/shared/registry/nodeTypes/CustomNodeType.ts +103 -0
- package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
- package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +48 -19
- package/lib/shared/registry/nodeTypes/IslandNodeType.ts +129 -0
- package/lib/shared/registry/nodeTypes/LinkNodeType.ts +21 -19
- package/lib/shared/registry/nodeTypes/ListNodeType.ts +117 -77
- package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
- package/lib/shared/registry/nodeTypes/MarkdownNodeType.ts +78 -0
- package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +12 -8
- package/lib/shared/registry/nodeTypes/index.ts +26 -3
- package/lib/shared/responsiveScaling.test.ts +16 -34
- package/lib/shared/responsiveScaling.ts +61 -42
- package/lib/shared/responsiveStyleUtils.test.ts +0 -1
- package/lib/shared/responsiveStyleUtils.ts +11 -13
- package/lib/shared/richtext/htmlToTiptap.test.ts +139 -130
- package/lib/shared/richtext/htmlToTiptap.ts +2 -4
- package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
- package/lib/shared/richtext/types.ts +1 -8
- package/lib/shared/slugTranslator.test.ts +13 -13
- package/lib/shared/slugTranslator.ts +12 -16
- package/lib/shared/slugify.ts +9 -15
- package/lib/shared/styleNodeUtils.test.ts +8 -8
- package/lib/shared/styleNodeUtils.ts +18 -20
- package/lib/shared/styleUtils.test.ts +87 -61
- package/lib/shared/styleUtils.ts +5 -6
- package/lib/shared/themeDefaults.test.ts +11 -14
- package/lib/shared/themeDefaults.ts +3 -4
- package/lib/shared/tree/PathBuilder.test.ts +63 -145
- package/lib/shared/tree/PathBuilder.ts +59 -47
- package/lib/shared/treePathUtils.test.ts +51 -12
- package/lib/shared/treePathUtils.ts +91 -60
- package/lib/shared/types/api.ts +105 -8
- package/lib/shared/types/cms.test.ts +34 -0
- package/lib/shared/types/cms.ts +90 -34
- package/lib/shared/types/comment.ts +49 -16
- package/lib/shared/types/components.ts +51 -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 +25 -2
- package/lib/shared/types/permissions.ts +139 -0
- package/lib/shared/types/styles.ts +0 -1
- package/lib/shared/types/variables.test.ts +4 -13
- package/lib/shared/types/variables.ts +51 -30
- package/lib/shared/types.ts +1 -2
- package/lib/shared/utilityClassConfig.ts +751 -321
- package/lib/shared/utilityClassMapper.durability.test.ts +117 -0
- package/lib/shared/utilityClassMapper.test.ts +433 -95
- package/lib/shared/utilityClassMapper.ts +322 -249
- package/lib/shared/utilityClassNames.test.ts +38 -0
- package/lib/shared/utilityClassNames.ts +458 -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 +12 -1
- package/lib/shared/validation/index.ts +1 -0
- package/lib/shared/validation/permissionsValidators.test.ts +49 -0
- package/lib/shared/validation/permissionsValidators.ts +49 -0
- package/lib/shared/validation/propValidator.test.ts +19 -21
- package/lib/shared/validation/propValidator.ts +13 -18
- package/lib/shared/validation/schemas.test.ts +64 -32
- package/lib/shared/validation/schemas.ts +616 -345
- package/lib/shared/validation/validators.test.ts +3 -8
- package/lib/shared/validation/validators.ts +89 -68
- package/lib/shared/viewportUnits.integration.test.ts +14 -10
- package/lib/shared/viewportUnits.test.ts +24 -23
- package/lib/shared/viewportUnits.ts +12 -5
- package/lib/test-utils/dom-setup.ts +1 -1
- package/lib/test-utils/factories/ConsoleMockFactory.ts +10 -14
- package/lib/test-utils/factories/DomMockFactory.ts +17 -23
- 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 +6 -10
- package/lib/test-utils/factories/StoreMockFactory.ts +18 -29
- 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 +13 -19
- package/lib/test-utils/mocks.ts +6 -4
- package/package.json +3 -5
- package/scripts/build-for-publish.mjs +2 -4
- package/scripts/build-meno-filter.ts +4 -7
- package/tsconfig.json +1 -0
- package/vite.config.ts +4 -4
- package/build-next.ts +0 -1361
- package/build-static.test.ts +0 -424
- package/build-static.ts +0 -1074
- package/dist/build-static.js +0 -36
- package/dist/chunks/chunk-2MHDV5BF.js +0 -251
- package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
- package/dist/chunks/chunk-AZQYF6KE.js +0 -559
- package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
- package/dist/chunks/chunk-GZHGVVW3.js +0 -322
- package/dist/chunks/chunk-GZHGVVW3.js.map +0 -7
- package/dist/chunks/chunk-H3GJ4H2U.js.map +0 -7
- package/dist/chunks/chunk-I7YIGZXT.js +0 -467
- package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
- package/dist/chunks/chunk-IGYR22T6.js +0 -6192
- package/dist/chunks/chunk-IGYR22T6.js.map +0 -7
- package/dist/chunks/chunk-JGP5A3Y5.js +0 -1136
- package/dist/chunks/chunk-JGP5A3Y5.js.map +0 -7
- package/dist/chunks/chunk-JGWFTO6P.js.map +0 -7
- package/dist/chunks/chunk-O3NAGJP4.js.map +0 -7
- package/dist/chunks/chunk-QB2LNO4W.js +0 -77
- package/dist/chunks/chunk-QB2LNO4W.js.map +0 -7
- package/dist/chunks/chunk-R6XHAFBF.js +0 -3821
- package/dist/chunks/chunk-R6XHAFBF.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/chunk-X754AHS5.js.map +0 -7
- package/dist/chunks/chunk-YBLHKYFF.js.map +0 -7
- package/dist/chunks/configService-R3OGU2UD.js +0 -13
- package/dist/chunks/configService-R3OGU2UD.js.map +0 -7
- package/dist/chunks/constants-STK2YBIW.js +0 -46
- package/dist/chunks/constants-STK2YBIW.js.map +0 -7
- package/dist/chunks/fs-JGINUXGL.js.map +0 -7
- package/dist/entries/server-router.js +0 -67
- package/dist/entries/server-router.js.map +0 -7
- package/entries/server-router.tsx +0 -81
- package/lib/server/providers/fileSystemPageProvider.ts +0 -160
- package/lib/server/webflow/buildWebflow.ts +0 -635
- package/lib/server/webflow/index.ts +0 -23
- package/lib/server/webflow/nodeToWebflow.test.ts +0 -3170
- package/lib/server/webflow/nodeToWebflow.ts +0 -2435
- package/lib/server/webflow/styleMapper.test.ts +0 -389
- package/lib/server/webflow/styleMapper.ts +0 -695
- package/lib/server/webflow/templateWrapper.ts +0 -49
- package/lib/server/webflow/types.ts +0 -396
- /package/dist/{build-static.js.map → chunks/fs-G3ANWEFP.js.map} +0 -0
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import type {
|
|
7
7
|
ComponentNode,
|
|
8
8
|
ComponentDefinition,
|
|
9
|
-
StructuredComponentDefinition,
|
|
10
9
|
PropDefinition,
|
|
11
10
|
HtmlNode,
|
|
12
11
|
ComponentInstanceNode,
|
|
@@ -30,14 +29,20 @@ import type {
|
|
|
30
29
|
import { responsiveStylesToTailwind, propertyToTailwind } from './tailwindMapper';
|
|
31
30
|
import type { BreakpointConfig } from '../../shared/breakpoints';
|
|
32
31
|
import type { ResponsiveScales } from '../../shared/responsiveScaling';
|
|
33
|
-
import { generateElementClassName
|
|
34
|
-
import { isVoidElement, hasIf
|
|
32
|
+
import { generateElementClassName } from '../../shared/elementClassName';
|
|
33
|
+
import { isVoidElement, hasIf } from '../../shared/nodeUtils';
|
|
35
34
|
import { deepMergeStyles } from '../../shared/styleNodeUtils';
|
|
36
35
|
import { NODE_TYPE, RAW_HTML_PREFIX } from '../../shared/constants';
|
|
37
36
|
import { extractInteractiveStyleMappings, hasInteractiveStyleMappings } from '../../shared/interactiveStyleMappings';
|
|
38
37
|
import type { ImageMetadataMap } from '../ssr/imageMetadata';
|
|
39
38
|
import { isI18nValue, resolveI18nValue, DEFAULT_I18N_CONFIG, buildLocalizedPath } from '../../shared/i18n';
|
|
40
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
transformCMSTemplate,
|
|
41
|
+
isTemplateExpression,
|
|
42
|
+
transformItemTemplate,
|
|
43
|
+
replaceItemMetaVars,
|
|
44
|
+
rewriteItemVar,
|
|
45
|
+
} from './templateTransformer';
|
|
41
46
|
import type { SlugMap } from '../../shared/slugTranslator';
|
|
42
47
|
import { buildSlugIndex, translatePath } from '../../shared/slugTranslator';
|
|
43
48
|
import { stripRawHtmlPrefixDeep, astroComponentName } from './astroEmitHelpers';
|
|
@@ -177,20 +182,12 @@ function localizeHref(href: string, ctx: AstroEmitContext): string {
|
|
|
177
182
|
|
|
178
183
|
function isStyleMapping(value: unknown): value is StyleMapping {
|
|
179
184
|
return (
|
|
180
|
-
typeof value === 'object' &&
|
|
181
|
-
value !== null &&
|
|
182
|
-
'_mapping' in value &&
|
|
183
|
-
(value as StyleMapping)._mapping === true
|
|
185
|
+
typeof value === 'object' && value !== null && '_mapping' in value && (value as StyleMapping)._mapping === true
|
|
184
186
|
);
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
function isLinkMapping(value: unknown): value is LinkMapping {
|
|
188
|
-
return (
|
|
189
|
-
typeof value === 'object' &&
|
|
190
|
-
value !== null &&
|
|
191
|
-
'_mapping' in value &&
|
|
192
|
-
(value as LinkMapping)._mapping === true
|
|
193
|
-
);
|
|
190
|
+
return typeof value === 'object' && value !== null && '_mapping' in value && (value as LinkMapping)._mapping === true;
|
|
194
191
|
}
|
|
195
192
|
|
|
196
193
|
/**
|
|
@@ -199,20 +196,18 @@ function isLinkMapping(value: unknown): value is LinkMapping {
|
|
|
199
196
|
function emitAttrValue(key: string, value: string, ctx: AstroEmitContext): string {
|
|
200
197
|
if (ctx.cmsMode && /\{\{cms\./.test(value)) {
|
|
201
198
|
const b = ctx.cmsEntryBinding || 'entry';
|
|
202
|
-
const w = (expr: string) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
199
|
+
const w = (expr: string) => (ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr);
|
|
203
200
|
const fullMatch = value.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
204
201
|
if (fullMatch) {
|
|
205
|
-
return `${key}={${w(`${b}.data.${fullMatch[1].trim()}`)}}`;
|
|
202
|
+
return `${key}={${w(`${b}.data.${(fullMatch[1] ?? '').trim()}`)}}`;
|
|
206
203
|
}
|
|
207
|
-
const replaced = value.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fp) =>
|
|
208
|
-
`\${${w(`${b}.data.${fp.trim()}`)}}`
|
|
209
|
-
);
|
|
204
|
+
const replaced = value.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fp) => `\${${w(`${b}.data.${fp.trim()}`)}}`);
|
|
210
205
|
return `${key}={\`${replaced}\`}`;
|
|
211
206
|
}
|
|
212
207
|
if (ctx.listItemBinding && /\{\{/.test(value)) {
|
|
213
208
|
const fullMatch = value.match(/^\{\{(.+)\}\}$/);
|
|
214
209
|
if (fullMatch) {
|
|
215
|
-
let expr = fullMatch[1].trim();
|
|
210
|
+
let expr = (fullMatch[1] ?? '').trim();
|
|
216
211
|
expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
217
212
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
218
213
|
return `${key}={${expr}}`;
|
|
@@ -229,17 +224,10 @@ function emitAttrValue(key: string, value: string, ctx: AstroEmitContext): strin
|
|
|
229
224
|
}
|
|
230
225
|
|
|
231
226
|
function isHtmlMapping(value: unknown): value is HtmlMapping {
|
|
232
|
-
return (
|
|
233
|
-
typeof value === 'object' &&
|
|
234
|
-
value !== null &&
|
|
235
|
-
'_mapping' in value &&
|
|
236
|
-
(value as HtmlMapping)._mapping === true
|
|
237
|
-
);
|
|
227
|
+
return typeof value === 'object' && value !== null && '_mapping' in value && (value as HtmlMapping)._mapping === true;
|
|
238
228
|
}
|
|
239
229
|
|
|
240
|
-
function isResponsiveStyle(
|
|
241
|
-
style: StyleObject | ResponsiveStyleObject
|
|
242
|
-
): style is ResponsiveStyleObject {
|
|
230
|
+
function isResponsiveStyle(style: StyleObject | ResponsiveStyleObject): style is ResponsiveStyleObject {
|
|
243
231
|
return 'base' in style || 'tablet' in style || 'mobile' in style;
|
|
244
232
|
}
|
|
245
233
|
|
|
@@ -266,7 +254,7 @@ function escapeTemplateLiteral(s: string): string {
|
|
|
266
254
|
* Get all style mappings from a style value, collecting { prop, property, values } tuples
|
|
267
255
|
*/
|
|
268
256
|
function collectStyleMappings(
|
|
269
|
-
style: StyleObject | ResponsiveStyleObject | undefined
|
|
257
|
+
style: StyleObject | ResponsiveStyleObject | undefined,
|
|
270
258
|
): Array<{ property: string; mapping: StyleMapping; breakpoint?: string }> {
|
|
271
259
|
if (!style) return [];
|
|
272
260
|
const result: Array<{ property: string; mapping: StyleMapping; breakpoint?: string }> = [];
|
|
@@ -299,17 +287,28 @@ function mappingToClassListEntries(
|
|
|
299
287
|
mapping: StyleMapping,
|
|
300
288
|
property: string,
|
|
301
289
|
breakpointPrefix: string,
|
|
302
|
-
ctx: AstroEmitContext
|
|
290
|
+
ctx: AstroEmitContext,
|
|
303
291
|
): string[] {
|
|
304
292
|
const entries: string[] = [];
|
|
305
293
|
const values = Object.entries(mapping.values);
|
|
306
294
|
if (values.length === 0) return entries;
|
|
307
295
|
|
|
296
|
+
// Mappings reference component props by bare identifier. Those identifiers
|
|
297
|
+
// only exist inside a component definition — on a page the reference would
|
|
298
|
+
// be an undefined variable (an Astro build error). Mirror the runtime, where
|
|
299
|
+
// resolveStyleMapping() receives no props at page scope and drops the
|
|
300
|
+
// property: emit no conditional entries outside a component def.
|
|
301
|
+
if (!ctx.isComponentDef) return entries;
|
|
302
|
+
|
|
308
303
|
// Generate utility class for each possible value
|
|
309
|
-
const propRef =
|
|
304
|
+
const propRef = mapping.prop;
|
|
310
305
|
|
|
311
306
|
if (values.length === 2) {
|
|
312
|
-
const
|
|
307
|
+
const entry1 = values[0];
|
|
308
|
+
const entry2 = values[1];
|
|
309
|
+
if (entry1 === undefined || entry2 === undefined) return entries;
|
|
310
|
+
const [val1, css1] = entry1;
|
|
311
|
+
const [, css2] = entry2;
|
|
313
312
|
// Generate Tailwind classes for each possible mapping value
|
|
314
313
|
const cls1 = getClassForValue(property, css1, breakpointPrefix);
|
|
315
314
|
const cls2 = getClassForValue(property, css2, breakpointPrefix);
|
|
@@ -342,11 +341,7 @@ function coerceValue(val: string): string | boolean {
|
|
|
342
341
|
/**
|
|
343
342
|
* Generate a Tailwind class name for a single property:value pair
|
|
344
343
|
*/
|
|
345
|
-
function getClassForValue(
|
|
346
|
-
property: string,
|
|
347
|
-
value: string | number,
|
|
348
|
-
breakpointPrefix: string
|
|
349
|
-
): string | null {
|
|
344
|
+
function getClassForValue(property: string, value: string | number, breakpointPrefix: string): string | null {
|
|
350
345
|
const twClass = propertyToTailwind(property, value);
|
|
351
346
|
if (!twClass) return null;
|
|
352
347
|
return breakpointPrefix ? `${breakpointPrefix}${twClass}` : twClass;
|
|
@@ -360,7 +355,7 @@ function buildClassAndStyleExpression(
|
|
|
360
355
|
style: StyleObject | ResponsiveStyleObject | undefined,
|
|
361
356
|
interactiveStyles: InteractiveStyles | undefined,
|
|
362
357
|
elementClass: string | null,
|
|
363
|
-
ctx: AstroEmitContext
|
|
358
|
+
ctx: AstroEmitContext,
|
|
364
359
|
): { classExpr: string; styleAttr: string } {
|
|
365
360
|
// Static Tailwind classes from non-mapping styles
|
|
366
361
|
const result = style
|
|
@@ -379,11 +374,12 @@ function buildClassAndStyleExpression(
|
|
|
379
374
|
const mappings = collectStyleMappings(style);
|
|
380
375
|
|
|
381
376
|
for (const { property, mapping, breakpoint } of mappings) {
|
|
382
|
-
const bpValue =
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
377
|
+
const bpValue =
|
|
378
|
+
breakpoint === 'tablet'
|
|
379
|
+
? (ctx.breakpoints.tablet?.breakpoint ?? 1024)
|
|
380
|
+
: breakpoint === 'mobile'
|
|
381
|
+
? (ctx.breakpoints.mobile?.breakpoint ?? 540)
|
|
382
|
+
: 0;
|
|
387
383
|
const prefix = bpValue ? `max-[${bpValue}px]:` : '';
|
|
388
384
|
const entries = mappingToClassListEntries(mapping, property, prefix, ctx);
|
|
389
385
|
conditionals.push(...entries);
|
|
@@ -392,17 +388,6 @@ function buildClassAndStyleExpression(
|
|
|
392
388
|
// Build style attribute for dynamic (template expression) styles
|
|
393
389
|
let styleAttr = '';
|
|
394
390
|
if (Object.keys(dynamicStyles).length > 0 && ctx.isComponentDef) {
|
|
395
|
-
const styleParts: string[] = [];
|
|
396
|
-
for (const [cssProp, value] of Object.entries(dynamicStyles)) {
|
|
397
|
-
// Convert {{propName}} to Astro expression in style
|
|
398
|
-
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
399
|
-
let trimmed = expr.trim();
|
|
400
|
-
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
401
|
-
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
402
|
-
return `\${${trimmed}}`;
|
|
403
|
-
});
|
|
404
|
-
styleParts.push(`${cssProp}: \${${resolved.includes('${') ? resolved.replace(/\$\{(.+?)\}/g, '$1') : `'${resolved}'`}}`);
|
|
405
|
-
}
|
|
406
391
|
// Build as template literal style attribute
|
|
407
392
|
const entries: string[] = [];
|
|
408
393
|
for (const [cssProp, value] of Object.entries(dynamicStyles)) {
|
|
@@ -418,7 +403,12 @@ function buildClassAndStyleExpression(
|
|
|
418
403
|
}
|
|
419
404
|
|
|
420
405
|
// Handle interactive style mappings: emit --is-N CSS variables as inline style
|
|
421
|
-
if (
|
|
406
|
+
if (
|
|
407
|
+
interactiveStyles &&
|
|
408
|
+
interactiveStyles.length > 0 &&
|
|
409
|
+
ctx.isComponentDef &&
|
|
410
|
+
hasInteractiveStyleMappings(interactiveStyles)
|
|
411
|
+
) {
|
|
422
412
|
const { mappings } = extractInteractiveStyleMappings(interactiveStyles);
|
|
423
413
|
if (mappings.length > 0) {
|
|
424
414
|
// Group mappings by prop for efficient ternary generation
|
|
@@ -428,9 +418,14 @@ function buildClassAndStyleExpression(
|
|
|
428
418
|
const varName = `--is-${variableIndex}`;
|
|
429
419
|
const entries = Object.entries(mapping.values);
|
|
430
420
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
421
|
+
const entry1 = entries[0];
|
|
422
|
+
const entry2 = entries[1];
|
|
423
|
+
if (entries.length === 2 && entry1 && entry2) {
|
|
424
|
+
const [val1, css1] = entry1;
|
|
425
|
+
const [_val2, css2] = entry2;
|
|
426
|
+
varParts.push(
|
|
427
|
+
`'${varName}': ${mapping.prop} === ${JSON.stringify(coerceValue(val1))} ? '${css1}' : '${css2}'`,
|
|
428
|
+
);
|
|
434
429
|
} else {
|
|
435
430
|
// Build a lookup object inline
|
|
436
431
|
const lookupEntries = entries
|
|
@@ -443,9 +438,7 @@ function buildClassAndStyleExpression(
|
|
|
443
438
|
|
|
444
439
|
// Merge with existing dynamic styles
|
|
445
440
|
if (varParts.length > 0) {
|
|
446
|
-
const existingStyleParts = styleAttr
|
|
447
|
-
? styleAttr.replace(/^ style=\{`/, '').replace(/`\}$/, '')
|
|
448
|
-
: '';
|
|
441
|
+
const existingStyleParts = styleAttr ? styleAttr.replace(/^ style=\{`/, '').replace(/`\}$/, '') : '';
|
|
449
442
|
const varStyleExpr = varParts.join(', ');
|
|
450
443
|
if (existingStyleParts) {
|
|
451
444
|
styleAttr = ` style={\`${existingStyleParts}; \${ Object.entries({${varStyleExpr}}).map(([k,v]) => \`\${k}:\${v}\`).join(';') }\`}`;
|
|
@@ -488,7 +481,7 @@ function resolveTemplate(text: string, ctx: AstroEmitContext): string {
|
|
|
488
481
|
// Check if entire text is a single {{expression}}
|
|
489
482
|
const fullMatch = text.match(/^\{\{(.+)\}\}$/);
|
|
490
483
|
if (fullMatch) {
|
|
491
|
-
let propName = fullMatch[1].trim();
|
|
484
|
+
let propName = (fullMatch[1] ?? '').trim();
|
|
492
485
|
if (ctx.listItemBinding) propName = rewriteItemVar(propName, ctx.listItemBinding);
|
|
493
486
|
if (ctx.listIndexVar) propName = replaceItemMetaVars(propName, ctx.listIndexVar, ctx.listSourceVar);
|
|
494
487
|
// Rich-text props contain HTML - render unescaped via set:html
|
|
@@ -516,10 +509,7 @@ function hasTemplates(text: string): boolean {
|
|
|
516
509
|
/**
|
|
517
510
|
* Build element class name for interactive styles
|
|
518
511
|
*/
|
|
519
|
-
function buildElementClass(
|
|
520
|
-
ctx: AstroEmitContext,
|
|
521
|
-
label: string | undefined
|
|
522
|
-
): string {
|
|
512
|
+
function buildElementClass(ctx: AstroEmitContext, label: string | undefined): string {
|
|
523
513
|
return generateElementClassName({
|
|
524
514
|
fileType: ctx.fileType,
|
|
525
515
|
fileName: ctx.fileName,
|
|
@@ -528,9 +518,7 @@ function buildElementClass(
|
|
|
528
518
|
});
|
|
529
519
|
}
|
|
530
520
|
|
|
531
|
-
function isResponsiveStyleObject(
|
|
532
|
-
style: StyleObject | ResponsiveStyleObject
|
|
533
|
-
): style is ResponsiveStyleObject {
|
|
521
|
+
function isResponsiveStyleObject(style: StyleObject | ResponsiveStyleObject): style is ResponsiveStyleObject {
|
|
534
522
|
return 'base' in style || 'tablet' in style || 'mobile' in style;
|
|
535
523
|
}
|
|
536
524
|
|
|
@@ -539,14 +527,10 @@ function isResponsiveStyleObject(
|
|
|
539
527
|
* link roots, or `props.style` for a component/link-instance root. Used to
|
|
540
528
|
* replicate SSR's per-breakpoint merge of an instance override into the root.
|
|
541
529
|
*/
|
|
542
|
-
function getComponentRootStyle(
|
|
543
|
-
def
|
|
544
|
-
): StyleObject | ResponsiveStyleObject | undefined {
|
|
545
|
-
const root = def?.component?.structure as
|
|
546
|
-
| { style?: unknown; props?: { style?: unknown } }
|
|
547
|
-
| undefined;
|
|
530
|
+
function getComponentRootStyle(def: ComponentDefinition | undefined): StyleObject | ResponsiveStyleObject | undefined {
|
|
531
|
+
const root = def?.component?.structure as { style?: unknown; props?: { style?: unknown } } | undefined;
|
|
548
532
|
if (!root || typeof root !== 'object') return undefined;
|
|
549
|
-
const s =
|
|
533
|
+
const s = root.style ?? root.props?.style;
|
|
550
534
|
return s && typeof s === 'object' ? (s as StyleObject | ResponsiveStyleObject) : undefined;
|
|
551
535
|
}
|
|
552
536
|
|
|
@@ -559,7 +543,7 @@ function getComponentRootStyle(
|
|
|
559
543
|
function hasNonEmptyStyle(style: StyleObject | ResponsiveStyleObject): boolean {
|
|
560
544
|
if (isResponsiveStyleObject(style)) {
|
|
561
545
|
return Object.values(style).some(
|
|
562
|
-
(branch) => !!branch && typeof branch === 'object' && Object.keys(branch as object).length > 0
|
|
546
|
+
(branch) => !!branch && typeof branch === 'object' && Object.keys(branch as object).length > 0,
|
|
563
547
|
);
|
|
564
548
|
}
|
|
565
549
|
return Object.keys(style).length > 0;
|
|
@@ -583,22 +567,19 @@ function stripTemplateExpressionStyle<T extends StyleObject | ResponsiveStyleObj
|
|
|
583
567
|
if (isResponsiveStyleObject(style)) {
|
|
584
568
|
const out: Record<string, unknown> = {};
|
|
585
569
|
for (const [bp, branch] of Object.entries(style as Record<string, unknown>)) {
|
|
586
|
-
out[bp] = branch && typeof branch === 'object'
|
|
587
|
-
? cleanFlat(branch as Record<string, unknown>)
|
|
588
|
-
: branch;
|
|
570
|
+
out[bp] = branch && typeof branch === 'object' ? cleanFlat(branch as Record<string, unknown>) : branch;
|
|
589
571
|
}
|
|
590
572
|
return out as T;
|
|
591
573
|
}
|
|
592
574
|
return cleanFlat(style as Record<string, unknown>) as T;
|
|
593
575
|
}
|
|
594
576
|
|
|
595
|
-
|
|
596
577
|
/**
|
|
597
578
|
* Build HTML attributes string from node attributes
|
|
598
579
|
*/
|
|
599
580
|
function buildAttributesString(
|
|
600
581
|
attributes: Record<string, string | number | boolean> | undefined,
|
|
601
|
-
ctx: AstroEmitContext
|
|
582
|
+
ctx: AstroEmitContext,
|
|
602
583
|
): string {
|
|
603
584
|
if (!attributes) return '';
|
|
604
585
|
const parts: string[] = [];
|
|
@@ -611,7 +592,7 @@ function buildAttributesString(
|
|
|
611
592
|
// Check if entire value is a single {{expression}}
|
|
612
593
|
const fullMatch = strVal.match(/^\{\{(.+)\}\}$/);
|
|
613
594
|
if (fullMatch) {
|
|
614
|
-
let expr = fullMatch[1].trim();
|
|
595
|
+
let expr = (fullMatch[1] ?? '').trim();
|
|
615
596
|
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
616
597
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
617
598
|
const propDef = ctx.componentProps[expr];
|
|
@@ -635,7 +616,7 @@ function buildAttributesString(
|
|
|
635
616
|
// List item binding: transform {{item.field}} in attributes
|
|
636
617
|
const fullMatch = strVal.match(/^\{\{(.+)\}\}$/);
|
|
637
618
|
if (fullMatch) {
|
|
638
|
-
let expr = fullMatch[1].trim();
|
|
619
|
+
let expr = (fullMatch[1] ?? '').trim();
|
|
639
620
|
expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
640
621
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
641
622
|
parts.push(`${key}={${expr} || undefined}`);
|
|
@@ -651,10 +632,10 @@ function buildAttributesString(
|
|
|
651
632
|
} else if (ctx.cmsMode && /\{\{cms\./.test(strVal)) {
|
|
652
633
|
// CMS mode: transform {{cms.field}} in attributes
|
|
653
634
|
const b = ctx.cmsEntryBinding || 'entry';
|
|
654
|
-
const w = (expr: string) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
635
|
+
const w = (expr: string) => (ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr);
|
|
655
636
|
const fullMatch = strVal.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
656
637
|
if (fullMatch) {
|
|
657
|
-
parts.push(`${key}={${w(`${b}.data.${fullMatch[1].trim()}`)}}`);
|
|
638
|
+
parts.push(`${key}={${w(`${b}.data.${(fullMatch[1] ?? '').trim()}`)}}`);
|
|
658
639
|
} else {
|
|
659
640
|
const replaced = strVal.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
660
641
|
return `\${${w(`${b}.data.${fieldPath.trim()}`)}}`;
|
|
@@ -666,7 +647,7 @@ function buildAttributesString(
|
|
|
666
647
|
}
|
|
667
648
|
}
|
|
668
649
|
}
|
|
669
|
-
return parts.length > 0 ?
|
|
650
|
+
return parts.length > 0 ? ` ${parts.join(' ')}` : '';
|
|
670
651
|
}
|
|
671
652
|
|
|
672
653
|
/**
|
|
@@ -702,7 +683,7 @@ function resolveI18n(value: unknown, ctx: AstroEmitContext): unknown {
|
|
|
702
683
|
*/
|
|
703
684
|
export function nodeToAstro(
|
|
704
685
|
node: ComponentNode | ComponentNode[] | string | number | null | undefined,
|
|
705
|
-
ctx: AstroEmitContext
|
|
686
|
+
ctx: AstroEmitContext,
|
|
706
687
|
): string {
|
|
707
688
|
if (node === null || node === undefined) return '';
|
|
708
689
|
|
|
@@ -718,6 +699,18 @@ export function nodeToAstro(
|
|
|
718
699
|
ctx.needsI18nResolver = true;
|
|
719
700
|
return `${ind(ctx)}{r(${JSON.stringify(stripRawHtmlPrefixDeep(resolved))})}\n`;
|
|
720
701
|
}
|
|
702
|
+
// Page context without a locale: resolve through the default locale
|
|
703
|
+
// (resolveTranslation falls back exact → default → first available →
|
|
704
|
+
// empty) instead of stringifying the i18n object to "[object Object]".
|
|
705
|
+
if (isI18nValue(resolved)) {
|
|
706
|
+
const config = ctx.i18nConfig ?? DEFAULT_I18N_CONFIG;
|
|
707
|
+
const fallbackLocale = ctx.defaultLocale ?? config.defaultLocale;
|
|
708
|
+
const fallbackResolved = resolveI18nValue(resolved, fallbackLocale, config);
|
|
709
|
+
if (typeof fallbackResolved === 'string') {
|
|
710
|
+
return nodeToAstro(fallbackResolved, ctx);
|
|
711
|
+
}
|
|
712
|
+
return `${ind(ctx)}${String(fallbackResolved ?? '')}\n`;
|
|
713
|
+
}
|
|
721
714
|
// If resolution returned a non-string (e.g. array), stringify it
|
|
722
715
|
return `${ind(ctx)}${String(resolved ?? '')}\n`;
|
|
723
716
|
}
|
|
@@ -726,7 +719,12 @@ export function nodeToAstro(
|
|
|
726
719
|
if (typeof node === 'string') {
|
|
727
720
|
// CMS mode: transform {{cms.field}} expressions to entry data access
|
|
728
721
|
if (ctx.cmsMode && isTemplateExpression(node) && /\{\{cms\./.test(node)) {
|
|
729
|
-
const transformed = transformCMSTemplate(
|
|
722
|
+
const transformed = transformCMSTemplate(
|
|
723
|
+
node,
|
|
724
|
+
ctx.cmsEntryBinding || 'entry',
|
|
725
|
+
ctx.cmsRichTextFields,
|
|
726
|
+
ctx.cmsWrapFn,
|
|
727
|
+
);
|
|
730
728
|
return `${ind(ctx)}${transformed}\n`;
|
|
731
729
|
}
|
|
732
730
|
// List item binding: transform {{item.field}} expressions
|
|
@@ -821,7 +819,7 @@ function splitImageClasses(allClasses: string[]): { pictureClasses: string[]; im
|
|
|
821
819
|
for (const cls of allClasses) {
|
|
822
820
|
// Strip responsive prefix (e.g., "md:object-cover" -> "object-cover") for matching
|
|
823
821
|
const baseCls = cls.includes(':') ? cls.split(':').pop()! : cls;
|
|
824
|
-
if (IMG_TAILWIND_PREFIXES.some(p => baseCls.startsWith(p)) || IMG_OPACITY_PATTERN.test(baseCls)) {
|
|
822
|
+
if (IMG_TAILWIND_PREFIXES.some((p) => baseCls.startsWith(p)) || IMG_OPACITY_PATTERN.test(baseCls)) {
|
|
825
823
|
imgClasses.push(cls);
|
|
826
824
|
} else {
|
|
827
825
|
pictureClasses.push(cls);
|
|
@@ -840,7 +838,7 @@ function extractPxWidth(val: unknown): number | null {
|
|
|
840
838
|
if (typeof val !== 'string') return null;
|
|
841
839
|
const match = val.trim().match(/^(\d+(?:\.\d+)?)px$/);
|
|
842
840
|
if (!match) return null;
|
|
843
|
-
const n = parseFloat(match[1]);
|
|
841
|
+
const n = parseFloat(match[1] ?? '');
|
|
844
842
|
return n > 0 ? n : null;
|
|
845
843
|
}
|
|
846
844
|
|
|
@@ -852,7 +850,7 @@ function extractPxWidth(val: unknown): number | null {
|
|
|
852
850
|
*/
|
|
853
851
|
function computeSizesAttribute(
|
|
854
852
|
style: StyleObject | ResponsiveStyleObject | undefined,
|
|
855
|
-
breakpoints: BreakpointConfig
|
|
853
|
+
breakpoints: BreakpointConfig,
|
|
856
854
|
): string {
|
|
857
855
|
if (!style) return DEFAULT_SIZES;
|
|
858
856
|
|
|
@@ -868,9 +866,7 @@ function computeSizesAttribute(
|
|
|
868
866
|
|
|
869
867
|
// Walk breakpoints from smallest to largest so the emitted media queries
|
|
870
868
|
// are ordered from narrowest to widest, with the unconditional base last.
|
|
871
|
-
const bpEntries = Object.entries(breakpoints).sort(
|
|
872
|
-
(a, b) => a[1].breakpoint - b[1].breakpoint
|
|
873
|
-
);
|
|
869
|
+
const bpEntries = Object.entries(breakpoints).sort((a, b) => a[1].breakpoint - b[1].breakpoint);
|
|
874
870
|
|
|
875
871
|
const parts: string[] = [];
|
|
876
872
|
// Track the "effective" width as we walk up: if a breakpoint doesn't set its
|
|
@@ -905,13 +901,34 @@ function computeSizesAttribute(
|
|
|
905
901
|
}
|
|
906
902
|
|
|
907
903
|
/**
|
|
908
|
-
* Merge additional CSS declarations into an existing ` style
|
|
909
|
-
* string. If no style attribute exists yet, builds one.
|
|
910
|
-
*
|
|
904
|
+
* Merge additional CSS declarations into an existing ` style` attribute
|
|
905
|
+
* string. If no style attribute exists yet, builds a static one. Handles all
|
|
906
|
+
* three attr shapes the emitter produces: static `style="..."`, dynamic
|
|
907
|
+
* template-literal `style={\`...\`}`, and dynamic expression `style={...}`.
|
|
908
|
+
* The inputs are raw CSS already escaped for HTML attribute context.
|
|
911
909
|
*/
|
|
912
910
|
function injectInlineStyle(styleAttr: string, extraCss: string): string {
|
|
913
911
|
if (!extraCss) return styleAttr;
|
|
914
912
|
if (!styleAttr) return ` style="${extraCss}"`;
|
|
913
|
+
|
|
914
|
+
// Dynamic template-literal style attr (` style={`...`}`): append the extra
|
|
915
|
+
// declarations inside the template literal so they survive the merge.
|
|
916
|
+
const dynLiteralMatch = styleAttr.match(/^ style=\{`([\s\S]*)`\}$/);
|
|
917
|
+
if (dynLiteralMatch) {
|
|
918
|
+
const existing = dynLiteralMatch[1] ?? '';
|
|
919
|
+
const trimmed = existing.trimEnd();
|
|
920
|
+
const sep = trimmed.length > 0 && !trimmed.endsWith(';') ? ';' : '';
|
|
921
|
+
return ` style={\`${existing}${sep}${extraCss}\`}`;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Dynamic expression style attr (` style={expr}`, e.g. the Object.entries()
|
|
925
|
+
// form for interactive style mappings): wrap the expression in a template
|
|
926
|
+
// literal and append the extra declarations after it.
|
|
927
|
+
const dynExprMatch = styleAttr.match(/^ style=\{([\s\S]*)\}$/);
|
|
928
|
+
if (dynExprMatch) {
|
|
929
|
+
return ` style={\`\${${dynExprMatch[1]}};${extraCss}\`}`;
|
|
930
|
+
}
|
|
931
|
+
|
|
915
932
|
return styleAttr.replace(/style="([^"]*)"/, (_, existing: string) => {
|
|
916
933
|
const trimmed = existing.trimEnd();
|
|
917
934
|
const sep = trimmed.length > 0 && !trimmed.endsWith(';') ? ';' : '';
|
|
@@ -932,7 +949,10 @@ const PICTURE_WIDTHS = [500, 800, 1080, 1600, 2400];
|
|
|
932
949
|
* identifier (`imgSubHeroPhoto`) for use as an ESM import variable.
|
|
933
950
|
*/
|
|
934
951
|
function imagePathToVarName(srcPath: string): string {
|
|
935
|
-
const stripped = srcPath
|
|
952
|
+
const stripped = srcPath
|
|
953
|
+
.replace(/^\/+/, '')
|
|
954
|
+
.replace(/^images\//, '')
|
|
955
|
+
.replace(/\.[^.]+$/, '');
|
|
936
956
|
const parts = stripped.split(/[/_\-\s.]+/).filter(Boolean);
|
|
937
957
|
if (parts.length === 0) return 'imgAsset';
|
|
938
958
|
const camel = parts
|
|
@@ -940,11 +960,11 @@ function imagePathToVarName(srcPath: string): string {
|
|
|
940
960
|
const clean = p.replace(/[^a-zA-Z0-9]/g, '');
|
|
941
961
|
if (!clean) return '';
|
|
942
962
|
if (i === 0) return clean.toLowerCase();
|
|
943
|
-
return clean[0].toUpperCase() + clean.slice(1).toLowerCase();
|
|
963
|
+
return (clean[0] ?? '').toUpperCase() + clean.slice(1).toLowerCase();
|
|
944
964
|
})
|
|
945
965
|
.join('');
|
|
946
966
|
if (!camel) return 'imgAsset';
|
|
947
|
-
return
|
|
967
|
+
return `img${(camel[0] ?? '').toUpperCase()}${camel.slice(1)}`;
|
|
948
968
|
}
|
|
949
969
|
|
|
950
970
|
/**
|
|
@@ -1003,13 +1023,11 @@ function registerStaticImageImport(src: string, ctx: AstroEmitContext): string {
|
|
|
1003
1023
|
* object-cover / opacity-* keep landing on the <img>. Returns null when the
|
|
1004
1024
|
* class expression is dynamic (class:list) — callers fall back to div wrap.
|
|
1005
1025
|
*/
|
|
1006
|
-
function splitStaticClassExpr(
|
|
1007
|
-
classExpr: string
|
|
1008
|
-
): { outerClasses: string[]; innerClasses: string[] } | null {
|
|
1026
|
+
function splitStaticClassExpr(classExpr: string): { outerClasses: string[]; innerClasses: string[] } | null {
|
|
1009
1027
|
if (classExpr.includes('class:list=')) return null;
|
|
1010
1028
|
const classMatch = classExpr.match(/class="([^"]*)"/);
|
|
1011
1029
|
if (!classMatch) return { outerClasses: [], innerClasses: [] };
|
|
1012
|
-
const all = classMatch[1].split(/\s+/).filter(Boolean);
|
|
1030
|
+
const all = (classMatch[1] ?? '').split(/\s+/).filter(Boolean);
|
|
1013
1031
|
const { pictureClasses, imgClasses } = splitImageClasses(all);
|
|
1014
1032
|
return { outerClasses: pictureClasses, innerClasses: imgClasses };
|
|
1015
1033
|
}
|
|
@@ -1018,10 +1036,7 @@ function splitStaticClassExpr(
|
|
|
1018
1036
|
* Format a static class+style pair as an Astro `pictureAttributes={{...}}`
|
|
1019
1037
|
* prop. `classValue` comes pre-split (outer layout classes only).
|
|
1020
1038
|
*/
|
|
1021
|
-
function formatPictureAttributesProp(
|
|
1022
|
-
classValue: string,
|
|
1023
|
-
styleAttr: string
|
|
1024
|
-
): string {
|
|
1039
|
+
function formatPictureAttributesProp(classValue: string, styleAttr: string): string {
|
|
1025
1040
|
const styleMatch = styleAttr.match(/style="([^"]*)"/);
|
|
1026
1041
|
const parts: string[] = [];
|
|
1027
1042
|
if (classValue) parts.push(`class: ${JSON.stringify(classValue)}`);
|
|
@@ -1045,7 +1060,7 @@ function emitStaticPictureImage(
|
|
|
1045
1060
|
ifExpr: string,
|
|
1046
1061
|
ifClose: string,
|
|
1047
1062
|
blurHash: string | undefined,
|
|
1048
|
-
ctx: AstroEmitContext
|
|
1063
|
+
ctx: AstroEmitContext,
|
|
1049
1064
|
): string {
|
|
1050
1065
|
const varName = registerStaticImageImport(src, ctx);
|
|
1051
1066
|
|
|
@@ -1093,9 +1108,7 @@ function emitStaticPictureImage(
|
|
|
1093
1108
|
// on the <picture>, inner img-specific classes as `class` on <Picture>.
|
|
1094
1109
|
if (split) {
|
|
1095
1110
|
const outerClassValue = split.outerClasses.join(' ');
|
|
1096
|
-
const innerClassAttr = split.innerClasses.length > 0
|
|
1097
|
-
? ` class="${split.innerClasses.join(' ')}"`
|
|
1098
|
-
: '';
|
|
1111
|
+
const innerClassAttr = split.innerClasses.length > 0 ? ` class="${split.innerClasses.join(' ')}"` : '';
|
|
1099
1112
|
const pictureAttrs = formatPictureAttributesProp(outerClassValue, styleAttr);
|
|
1100
1113
|
return `${ifExpr}${ind(ctx)}<Picture${pictureAttrs} src={${varName}}${altAttr}${innerClassAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr} />\n${ifClose}`;
|
|
1101
1114
|
}
|
|
@@ -1113,10 +1126,7 @@ function emitImageNode(node: HtmlNode, ctx: AstroEmitContext): string {
|
|
|
1113
1126
|
|
|
1114
1127
|
// Element class for interactive styles
|
|
1115
1128
|
let elementClass: string | null = null;
|
|
1116
|
-
if (
|
|
1117
|
-
(node.interactiveStyles && node.interactiveStyles.length > 0) ||
|
|
1118
|
-
node.generateElementClass
|
|
1119
|
-
) {
|
|
1129
|
+
if ((node.interactiveStyles && node.interactiveStyles.length > 0) || node.generateElementClass) {
|
|
1120
1130
|
elementClass = buildElementClass(ctx, node.label);
|
|
1121
1131
|
if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
|
|
1122
1132
|
ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles as InteractiveStyles);
|
|
@@ -1127,7 +1137,7 @@ function emitImageNode(node: HtmlNode, ctx: AstroEmitContext): string {
|
|
|
1127
1137
|
style,
|
|
1128
1138
|
node.interactiveStyles as InteractiveStyles | undefined,
|
|
1129
1139
|
elementClass,
|
|
1130
|
-
ctx
|
|
1140
|
+
ctx,
|
|
1131
1141
|
);
|
|
1132
1142
|
|
|
1133
1143
|
// Extract image-specific attributes
|
|
@@ -1166,7 +1176,7 @@ function emitImageNode(node: HtmlNode, ctx: AstroEmitContext): string {
|
|
|
1166
1176
|
emitIfOpen(node, ctx),
|
|
1167
1177
|
emitIfClose(node, ctx),
|
|
1168
1178
|
metadata?.blurHash,
|
|
1169
|
-
ctx
|
|
1179
|
+
ctx,
|
|
1170
1180
|
);
|
|
1171
1181
|
}
|
|
1172
1182
|
|
|
@@ -1198,12 +1208,8 @@ function emitImageNode(node: HtmlNode, ctx: AstroEmitContext): string {
|
|
|
1198
1208
|
// is a replaced element and doesn't paint CSS backgrounds reliably).
|
|
1199
1209
|
// Once the real image loads we clear the background on the wrapper so the
|
|
1200
1210
|
// low-quality placeholder disappears.
|
|
1201
|
-
const blurWrapperCss = hasBlur
|
|
1202
|
-
|
|
1203
|
-
: '';
|
|
1204
|
-
const blurOnload = hasBlur
|
|
1205
|
-
? ` onload="this.parentElement.style.backgroundImage=''"`
|
|
1206
|
-
: '';
|
|
1211
|
+
const blurWrapperCss = hasBlur ? `background-image:url(${escapeJSX(metadata!.blurHash!)});background-size:cover` : '';
|
|
1212
|
+
const blurOnload = hasBlur ? ` onload="this.parentElement.style.backgroundImage=''"` : '';
|
|
1207
1213
|
|
|
1208
1214
|
// Conditional rendering
|
|
1209
1215
|
const ifExpr = emitIfOpen(node, ctx);
|
|
@@ -1225,7 +1231,7 @@ function emitImageNode(node: HtmlNode, ctx: AstroEmitContext): string {
|
|
|
1225
1231
|
pictureClassExpr = classExpr;
|
|
1226
1232
|
imgClassAttr = ` class="${imgFillClasses.join(' ')}"`;
|
|
1227
1233
|
} else {
|
|
1228
|
-
const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
|
|
1234
|
+
const allClasses = classMatch ? (classMatch[1] ?? '').split(/\s+/).filter(Boolean) : [];
|
|
1229
1235
|
const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
|
|
1230
1236
|
const fullImgClasses = [...imgClasses, ...imgFillClasses];
|
|
1231
1237
|
pictureClassExpr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(' ')}"` : '';
|
|
@@ -1302,17 +1308,19 @@ function emitHtmlNode(node: HtmlNode, ctx: AstroEmitContext): string {
|
|
|
1302
1308
|
|
|
1303
1309
|
// Element class for interactive styles
|
|
1304
1310
|
let elementClass: string | null = null;
|
|
1305
|
-
if (
|
|
1306
|
-
(node.interactiveStyles && node.interactiveStyles.length > 0) ||
|
|
1307
|
-
node.generateElementClass
|
|
1308
|
-
) {
|
|
1311
|
+
if ((node.interactiveStyles && node.interactiveStyles.length > 0) || node.generateElementClass) {
|
|
1309
1312
|
elementClass = buildElementClass(ctx, label);
|
|
1310
1313
|
if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
|
|
1311
1314
|
ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles as InteractiveStyles);
|
|
1312
1315
|
}
|
|
1313
1316
|
}
|
|
1314
1317
|
|
|
1315
|
-
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1318
|
+
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1319
|
+
style,
|
|
1320
|
+
node.interactiveStyles as InteractiveStyles | undefined,
|
|
1321
|
+
elementClass,
|
|
1322
|
+
ctx,
|
|
1323
|
+
);
|
|
1316
1324
|
const attrs = buildAttributesString(node.attributes, ctx);
|
|
1317
1325
|
|
|
1318
1326
|
// Dynamic tags use the variable name directly (capitalized, defined in frontmatter)
|
|
@@ -1354,7 +1362,7 @@ function emitComponentInstance(node: ComponentInstanceNode, ctx: AstroEmitContex
|
|
|
1354
1362
|
if (typeof value === 'string' && hasTemplates(value) && ctx.isComponentDef) {
|
|
1355
1363
|
const fullMatch = value.match(/^\{\{(.+)\}\}$/);
|
|
1356
1364
|
if (fullMatch) {
|
|
1357
|
-
let expr = fullMatch[1].trim();
|
|
1365
|
+
let expr = (fullMatch[1] ?? '').trim();
|
|
1358
1366
|
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
1359
1367
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
1360
1368
|
propParts.push(`${key}={${expr}}`);
|
|
@@ -1369,10 +1377,10 @@ function emitComponentInstance(node: ComponentInstanceNode, ctx: AstroEmitContex
|
|
|
1369
1377
|
}
|
|
1370
1378
|
} else if (typeof value === 'string' && ctx.cmsMode && /\{\{cms\./.test(value)) {
|
|
1371
1379
|
const b = ctx.cmsEntryBinding || 'entry';
|
|
1372
|
-
const w = (expr: string) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
1380
|
+
const w = (expr: string) => (ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr);
|
|
1373
1381
|
const fullMatch = value.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
1374
1382
|
if (fullMatch) {
|
|
1375
|
-
propParts.push(`${key}={${w(`${b}.data.${fullMatch[1].trim()}`)}}`);
|
|
1383
|
+
propParts.push(`${key}={${w(`${b}.data.${(fullMatch[1] ?? '').trim()}`)}}`);
|
|
1376
1384
|
} else {
|
|
1377
1385
|
const replaced = value.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
1378
1386
|
return `\${${w(`${b}.data.${fieldPath.trim()}`)}}`;
|
|
@@ -1433,9 +1441,9 @@ function emitComponentInstance(node: ComponentInstanceNode, ctx: AstroEmitContex
|
|
|
1433
1441
|
// root are dropped downstream (styleObjectToCSS skips mappings) /
|
|
1434
1442
|
// stripped here, falling back to the component's own emission.
|
|
1435
1443
|
const rootStyle = getComponentRootStyle(ctx.globalComponents[node.component]);
|
|
1436
|
-
const merged = (rootStyle
|
|
1437
|
-
|
|
1438
|
-
|
|
1444
|
+
const merged = (rootStyle ? deepMergeStyles(rootStyle, instanceStyle!) : instanceStyle!) as
|
|
1445
|
+
| StyleObject
|
|
1446
|
+
| ResponsiveStyleObject;
|
|
1439
1447
|
const cssSafe = stripTemplateExpressionStyle(merged);
|
|
1440
1448
|
if (hasNonEmptyStyle(cssSafe)) rules.push({ style: cssSafe }); // no prefix/postfix → `.cls {…}`
|
|
1441
1449
|
}
|
|
@@ -1448,7 +1456,7 @@ function emitComponentInstance(node: ComponentInstanceNode, ctx: AstroEmitContex
|
|
|
1448
1456
|
}
|
|
1449
1457
|
}
|
|
1450
1458
|
|
|
1451
|
-
const propsStr = propParts.length > 0 ?
|
|
1459
|
+
const propsStr = propParts.length > 0 ? ` ${propParts.join(' ')}` : '';
|
|
1452
1460
|
|
|
1453
1461
|
// Reset elementPath to [0] when entering a component instance, matching SSR's
|
|
1454
1462
|
// renderComponent behavior. This ensures hash-based element class names for
|
|
@@ -1460,22 +1468,14 @@ function emitComponentInstance(node: ComponentInstanceNode, ctx: AstroEmitContex
|
|
|
1460
1468
|
return `${ifExpr}${ind(ctx)}<${name}${propsStr} />\n${emitIfClose(node, ctx)}`;
|
|
1461
1469
|
}
|
|
1462
1470
|
|
|
1463
|
-
return (
|
|
1464
|
-
`${ifExpr}${ind(ctx)}<${name}${propsStr}>\n` +
|
|
1465
|
-
children +
|
|
1466
|
-
`${ind(ctx)}</${name}>\n${emitIfClose(node, ctx)}`
|
|
1467
|
-
);
|
|
1471
|
+
return `${ifExpr}${ind(ctx)}<${name}${propsStr}>\n${children}${ind(ctx)}</${name}>\n${emitIfClose(node, ctx)}`;
|
|
1468
1472
|
}
|
|
1469
1473
|
|
|
1470
1474
|
function emitSlotMarker(node: SlotMarker, ctx: AstroEmitContext): string {
|
|
1471
1475
|
if (node.default) {
|
|
1472
1476
|
const defaultContent = emitChildren(node.default as (ComponentNode | string)[] | string | undefined, ctx);
|
|
1473
1477
|
if (defaultContent.trim()) {
|
|
1474
|
-
return (
|
|
1475
|
-
`${ind(ctx)}<slot>\n` +
|
|
1476
|
-
defaultContent +
|
|
1477
|
-
`${ind(ctx)}</slot>\n`
|
|
1478
|
-
);
|
|
1478
|
+
return `${ind(ctx)}<slot>\n${defaultContent}${ind(ctx)}</slot>\n`;
|
|
1479
1479
|
}
|
|
1480
1480
|
}
|
|
1481
1481
|
return `${ind(ctx)}<slot />\n`;
|
|
@@ -1486,17 +1486,19 @@ function emitEmbedNode(node: EmbedNode, ctx: AstroEmitContext): string {
|
|
|
1486
1486
|
const style = node.style as StyleObject | ResponsiveStyleObject | undefined;
|
|
1487
1487
|
|
|
1488
1488
|
let elementClass: string | null = null;
|
|
1489
|
-
if (
|
|
1490
|
-
(node.interactiveStyles && node.interactiveStyles.length > 0) ||
|
|
1491
|
-
node.generateElementClass
|
|
1492
|
-
) {
|
|
1489
|
+
if ((node.interactiveStyles && node.interactiveStyles.length > 0) || node.generateElementClass) {
|
|
1493
1490
|
elementClass = buildElementClass(ctx, node.label);
|
|
1494
1491
|
if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
|
|
1495
1492
|
ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles as InteractiveStyles);
|
|
1496
1493
|
}
|
|
1497
1494
|
}
|
|
1498
1495
|
|
|
1499
|
-
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1496
|
+
const { classExpr, styleAttr: _styleAttr } = buildClassAndStyleExpression(
|
|
1497
|
+
style,
|
|
1498
|
+
node.interactiveStyles as InteractiveStyles | undefined,
|
|
1499
|
+
elementClass,
|
|
1500
|
+
ctx,
|
|
1501
|
+
);
|
|
1500
1502
|
const attrs = buildAttributesString(node.attributes, ctx);
|
|
1501
1503
|
|
|
1502
1504
|
// Handle HTML mapping (prop-dependent content)
|
|
@@ -1515,7 +1517,7 @@ function emitEmbedNode(node: EmbedNode, ctx: AstroEmitContext): string {
|
|
|
1515
1517
|
if (typeof node.html === 'string' && hasTemplates(node.html) && ctx.isComponentDef) {
|
|
1516
1518
|
const fullMatch = node.html.match(/^\{\{(.+)\}\}$/);
|
|
1517
1519
|
if (fullMatch) {
|
|
1518
|
-
let propRef = fullMatch[1].trim();
|
|
1520
|
+
let propRef = (fullMatch[1] ?? '').trim();
|
|
1519
1521
|
if (ctx.listItemBinding) propRef = rewriteItemVar(propRef, ctx.listItemBinding);
|
|
1520
1522
|
if (ctx.listIndexVar) propRef = replaceItemMetaVars(propRef, ctx.listIndexVar, ctx.listSourceVar);
|
|
1521
1523
|
|
|
@@ -1561,10 +1563,7 @@ function emitLinkNode(node: LinkNode, ctx: AstroEmitContext): string {
|
|
|
1561
1563
|
const style = node.style as StyleObject | ResponsiveStyleObject | undefined;
|
|
1562
1564
|
|
|
1563
1565
|
let elementClass: string | null = null;
|
|
1564
|
-
if (
|
|
1565
|
-
(node.interactiveStyles && node.interactiveStyles.length > 0) ||
|
|
1566
|
-
node.generateElementClass
|
|
1567
|
-
) {
|
|
1566
|
+
if ((node.interactiveStyles && node.interactiveStyles.length > 0) || node.generateElementClass) {
|
|
1568
1567
|
elementClass = buildElementClass(ctx, node.label);
|
|
1569
1568
|
if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
|
|
1570
1569
|
ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles as InteractiveStyles);
|
|
@@ -1572,7 +1571,12 @@ function emitLinkNode(node: LinkNode, ctx: AstroEmitContext): string {
|
|
|
1572
1571
|
}
|
|
1573
1572
|
|
|
1574
1573
|
// Build class expression with olink base class
|
|
1575
|
-
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1574
|
+
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1575
|
+
style,
|
|
1576
|
+
node.interactiveStyles as InteractiveStyles | undefined,
|
|
1577
|
+
elementClass,
|
|
1578
|
+
ctx,
|
|
1579
|
+
);
|
|
1576
1580
|
let finalClassExpr = classExpr;
|
|
1577
1581
|
if (!classExpr.includes('olink')) {
|
|
1578
1582
|
if (classExpr) {
|
|
@@ -1601,7 +1605,7 @@ function emitLinkNode(node: LinkNode, ctx: AstroEmitContext): string {
|
|
|
1601
1605
|
if (hasTemplates(href) && ctx.isComponentDef) {
|
|
1602
1606
|
const fullMatch = href.match(/^\{\{(.+)\}\}$/);
|
|
1603
1607
|
if (fullMatch) {
|
|
1604
|
-
let expr = fullMatch[1].trim();
|
|
1608
|
+
let expr = (fullMatch[1] ?? '').trim();
|
|
1605
1609
|
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
1606
1610
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
1607
1611
|
const propDef = ctx.componentProps[expr];
|
|
@@ -1622,10 +1626,10 @@ function emitLinkNode(node: LinkNode, ctx: AstroEmitContext): string {
|
|
|
1622
1626
|
}
|
|
1623
1627
|
} else if (ctx.cmsMode && /\{\{cms\./.test(href)) {
|
|
1624
1628
|
const b = ctx.cmsEntryBinding || 'entry';
|
|
1625
|
-
const w = (expr: string) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
1629
|
+
const w = (expr: string) => (ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr);
|
|
1626
1630
|
const fullMatch = href.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
1627
1631
|
if (fullMatch) {
|
|
1628
|
-
hrefAttr = ` href={${w(`${b}.data.${fullMatch[1].trim()}`)}}`;
|
|
1632
|
+
hrefAttr = ` href={${w(`${b}.data.${(fullMatch[1] ?? '').trim()}`)}}`;
|
|
1629
1633
|
} else {
|
|
1630
1634
|
const replaced = href.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
1631
1635
|
return `\${${w(`${b}.data.${fieldPath.trim()}`)}}`;
|
|
@@ -1660,10 +1664,7 @@ function emitImageTypeNode(node: any, ctx: AstroEmitContext): string {
|
|
|
1660
1664
|
const style = node.style as StyleObject | ResponsiveStyleObject | undefined;
|
|
1661
1665
|
|
|
1662
1666
|
let elementClass: string | null = null;
|
|
1663
|
-
if (
|
|
1664
|
-
(node.interactiveStyles && node.interactiveStyles.length > 0) ||
|
|
1665
|
-
node.generateElementClass
|
|
1666
|
-
) {
|
|
1667
|
+
if ((node.interactiveStyles && node.interactiveStyles.length > 0) || node.generateElementClass) {
|
|
1667
1668
|
elementClass = buildElementClass(ctx, node.label);
|
|
1668
1669
|
if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
|
|
1669
1670
|
ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles as InteractiveStyles);
|
|
@@ -1674,7 +1675,7 @@ function emitImageTypeNode(node: any, ctx: AstroEmitContext): string {
|
|
|
1674
1675
|
style,
|
|
1675
1676
|
node.interactiveStyles as InteractiveStyles | undefined,
|
|
1676
1677
|
elementClass,
|
|
1677
|
-
ctx
|
|
1678
|
+
ctx,
|
|
1678
1679
|
);
|
|
1679
1680
|
|
|
1680
1681
|
const src = node.src as string | undefined;
|
|
@@ -1694,7 +1695,7 @@ function emitImageTypeNode(node: any, ctx: AstroEmitContext): string {
|
|
|
1694
1695
|
'',
|
|
1695
1696
|
'',
|
|
1696
1697
|
staticMeta.blurHash,
|
|
1697
|
-
ctx
|
|
1698
|
+
ctx,
|
|
1698
1699
|
);
|
|
1699
1700
|
}
|
|
1700
1701
|
|
|
@@ -1718,17 +1719,13 @@ function emitImageTypeNode(node: any, ctx: AstroEmitContext): string {
|
|
|
1718
1719
|
const hasBlur = !!metadata.blurHash;
|
|
1719
1720
|
const useWrapper = hasAvif || hasBlur;
|
|
1720
1721
|
|
|
1721
|
-
const blurWrapperCss = hasBlur
|
|
1722
|
-
|
|
1723
|
-
: '';
|
|
1724
|
-
const blurOnload = hasBlur
|
|
1725
|
-
? ` onload="this.parentElement.style.backgroundImage=''"`
|
|
1726
|
-
: '';
|
|
1722
|
+
const blurWrapperCss = hasBlur ? `background-image:url(${escapeJSX(metadata.blurHash!)});background-size:cover` : '';
|
|
1723
|
+
const blurOnload = hasBlur ? ` onload="this.parentElement.style.backgroundImage=''"` : '';
|
|
1727
1724
|
|
|
1728
1725
|
if (useWrapper) {
|
|
1729
1726
|
const imgFillClasses = IMG_FILL_CLASSES.slice();
|
|
1730
1727
|
const classMatch = classExpr.match(/class="([^"]*)"/);
|
|
1731
|
-
const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
|
|
1728
|
+
const allClasses = classMatch ? (classMatch[1] ?? '').split(/\s+/).filter(Boolean) : [];
|
|
1732
1729
|
const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
|
|
1733
1730
|
const fullImgClasses = [...imgClasses, ...imgFillClasses];
|
|
1734
1731
|
|
|
@@ -1787,7 +1784,7 @@ function emitListNode(node: ListNode, ctx: AstroEmitContext): string {
|
|
|
1787
1784
|
let source = node.source || 'items';
|
|
1788
1785
|
const templateMatch = source.match(/^\{\{(.+)\}\}$/);
|
|
1789
1786
|
if (templateMatch) {
|
|
1790
|
-
source = templateMatch[1].trim();
|
|
1787
|
+
source = (templateMatch[1] ?? '').trim();
|
|
1791
1788
|
}
|
|
1792
1789
|
|
|
1793
1790
|
// Build the .map() source expression (compute before children so ctx has it)
|
|
@@ -1812,19 +1809,17 @@ function emitListNode(node: ListNode, ctx: AstroEmitContext): string {
|
|
|
1812
1809
|
};
|
|
1813
1810
|
|
|
1814
1811
|
const children = node.children
|
|
1815
|
-
? (node.children as (ComponentNode | string)[])
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1812
|
+
? (node.children as (ComponentNode | string)[])
|
|
1813
|
+
.map((child, i) => {
|
|
1814
|
+
const childCtx = { ...innerCtx, elementPath: [...ctx.elementPath, i] };
|
|
1815
|
+
const out = nodeToAstro(child, childCtx);
|
|
1816
|
+
if (childCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1817
|
+
return out;
|
|
1818
|
+
})
|
|
1819
|
+
.join('')
|
|
1821
1820
|
: '';
|
|
1822
1821
|
|
|
1823
|
-
return (
|
|
1824
|
-
`${ind(ctx)}{${mapSource}.map((${itemAs}, ${indexVar}) => (\n` +
|
|
1825
|
-
children +
|
|
1826
|
-
`${ind(ctx)}))}\n`
|
|
1827
|
-
);
|
|
1822
|
+
return `${ind(ctx)}{${mapSource}.map((${itemAs}, ${indexVar}) => (\n${children}${ind(ctx)}))}\n`;
|
|
1828
1823
|
}
|
|
1829
1824
|
|
|
1830
1825
|
/**
|
|
@@ -1876,8 +1871,7 @@ function emitCollectionListNode(node: ListNode, ctx: AstroEmitContext): string {
|
|
|
1876
1871
|
// shape the templates expect ({{item.field}} → item.field), and synthesize the
|
|
1877
1872
|
// `_url`/`_id` meta the CMS data model exposes. Filter/sort above operate on the
|
|
1878
1873
|
// raw entries (e.data.*); this map runs last so it sees the final set.
|
|
1879
|
-
const urlExpr = ctx.collectionUrlExpr?.get(source)
|
|
1880
|
-
?? `\`/${source}/\${e.data.slug ?? e.id}\``;
|
|
1874
|
+
const urlExpr = ctx.collectionUrlExpr?.get(source) ?? `\`/${source}/\${e.data.slug ?? e.id}\``;
|
|
1881
1875
|
queryChain += `.then(items => items.map((e) => ({ ...e.data, _id: e.id, _url: ${urlExpr} })))`;
|
|
1882
1876
|
|
|
1883
1877
|
ctx.frontmatterLines.push(`const ${collectionVar} = ${queryChain};`);
|
|
@@ -1896,19 +1890,17 @@ function emitCollectionListNode(node: ListNode, ctx: AstroEmitContext): string {
|
|
|
1896
1890
|
};
|
|
1897
1891
|
|
|
1898
1892
|
const children = node.children
|
|
1899
|
-
? (node.children as (ComponentNode | string)[])
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1893
|
+
? (node.children as (ComponentNode | string)[])
|
|
1894
|
+
.map((child, i) => {
|
|
1895
|
+
const childCtx = { ...innerCtx, elementPath: [...ctx.elementPath, i] };
|
|
1896
|
+
const out = nodeToAstro(child, childCtx);
|
|
1897
|
+
if (childCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1898
|
+
return out;
|
|
1899
|
+
})
|
|
1900
|
+
.join('')
|
|
1905
1901
|
: '';
|
|
1906
1902
|
|
|
1907
|
-
return (
|
|
1908
|
-
`${ind(ctx)}{${collectionVar}.map((${itemAs}, ${indexVar}) => (\n` +
|
|
1909
|
-
children +
|
|
1910
|
-
`${ind(ctx)}))}\n`
|
|
1911
|
-
);
|
|
1903
|
+
return `${ind(ctx)}{${collectionVar}.map((${itemAs}, ${indexVar}) => (\n${children}${ind(ctx)}))}\n`;
|
|
1912
1904
|
}
|
|
1913
1905
|
|
|
1914
1906
|
/**
|
|
@@ -1932,7 +1924,10 @@ function emitLocaleListNode(node: LocaleListNode, ctx: AstroEmitContext): string
|
|
|
1932
1924
|
const style = node.style as StyleObject | ResponsiveStyleObject | undefined;
|
|
1933
1925
|
|
|
1934
1926
|
let elementClass: string | null = null;
|
|
1935
|
-
if (
|
|
1927
|
+
if (
|
|
1928
|
+
(node.interactiveStyles && (node.interactiveStyles as InteractiveStyles).length > 0) ||
|
|
1929
|
+
node.generateElementClass
|
|
1930
|
+
) {
|
|
1936
1931
|
elementClass = buildElementClass(ctx, node.label);
|
|
1937
1932
|
if (elementClass && (node.interactiveStyles as InteractiveStyles)?.length && ctx.collectedInteractiveStyles) {
|
|
1938
1933
|
ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles as InteractiveStyles);
|
|
@@ -1943,22 +1938,28 @@ function emitLocaleListNode(node: LocaleListNode, ctx: AstroEmitContext): string
|
|
|
1943
1938
|
style,
|
|
1944
1939
|
node.interactiveStyles as InteractiveStyles | undefined,
|
|
1945
1940
|
elementClass,
|
|
1946
|
-
ctx
|
|
1941
|
+
ctx,
|
|
1947
1942
|
);
|
|
1948
1943
|
|
|
1949
1944
|
// Build item classes
|
|
1950
1945
|
const itemStyle = node.itemStyle as StyleObject | ResponsiveStyleObject | undefined;
|
|
1951
|
-
const itemResult = itemStyle
|
|
1946
|
+
const itemResult = itemStyle
|
|
1947
|
+
? responsiveStylesToTailwind(itemStyle, ctx.breakpoints, ctx.responsiveScales)
|
|
1948
|
+
: { classes: [], dynamicStyles: {} };
|
|
1952
1949
|
const itemClasses = itemResult.classes;
|
|
1953
1950
|
|
|
1954
1951
|
// Build active item classes (item + active combined)
|
|
1955
1952
|
const activeItemStyle = node.activeItemStyle as StyleObject | ResponsiveStyleObject | undefined;
|
|
1956
|
-
const activeResult = activeItemStyle
|
|
1953
|
+
const activeResult = activeItemStyle
|
|
1954
|
+
? responsiveStylesToTailwind(activeItemStyle, ctx.breakpoints, ctx.responsiveScales)
|
|
1955
|
+
: { classes: [], dynamicStyles: {} };
|
|
1957
1956
|
const activeItemClasses = [...itemClasses, ...activeResult.classes];
|
|
1958
1957
|
|
|
1959
1958
|
// Build separator classes
|
|
1960
1959
|
const separatorStyle = node.separatorStyle as StyleObject | ResponsiveStyleObject | undefined;
|
|
1961
|
-
const sepResult = separatorStyle
|
|
1960
|
+
const sepResult = separatorStyle
|
|
1961
|
+
? responsiveStylesToTailwind(separatorStyle, ctx.breakpoints, ctx.responsiveScales)
|
|
1962
|
+
: { classes: [], dynamicStyles: {} };
|
|
1962
1963
|
const separatorClasses = sepResult.classes;
|
|
1963
1964
|
|
|
1964
1965
|
// Build locale icon map
|
|
@@ -1971,7 +1972,9 @@ function emitLocaleListNode(node: LocaleListNode, ctx: AstroEmitContext): string
|
|
|
1971
1972
|
|
|
1972
1973
|
// Flag classes
|
|
1973
1974
|
const flagStyle = node.flagStyle as StyleObject | ResponsiveStyleObject | undefined;
|
|
1974
|
-
const flagResult = flagStyle
|
|
1975
|
+
const flagResult = flagStyle
|
|
1976
|
+
? responsiveStylesToTailwind(flagStyle, ctx.breakpoints, ctx.responsiveScales)
|
|
1977
|
+
: { classes: [], dynamicStyles: {} };
|
|
1975
1978
|
const flagClasses = flagResult.classes;
|
|
1976
1979
|
|
|
1977
1980
|
// Build links
|
|
@@ -1993,9 +1996,15 @@ function emitLocaleListNode(node: LocaleListNode, ctx: AstroEmitContext): string
|
|
|
1993
1996
|
// Display text
|
|
1994
1997
|
let displayText: string;
|
|
1995
1998
|
switch (displayType) {
|
|
1996
|
-
case 'code':
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
+
case 'code':
|
|
2000
|
+
displayText = code.toUpperCase();
|
|
2001
|
+
break;
|
|
2002
|
+
case 'name':
|
|
2003
|
+
displayText = localeConfig.name;
|
|
2004
|
+
break;
|
|
2005
|
+
default:
|
|
2006
|
+
displayText = localeConfig.nativeName;
|
|
2007
|
+
break;
|
|
1999
2008
|
}
|
|
2000
2009
|
|
|
2001
2010
|
// Build link content
|
|
@@ -2007,7 +2016,9 @@ function emitLocaleListNode(node: LocaleListNode, ctx: AstroEmitContext): string
|
|
|
2007
2016
|
}
|
|
2008
2017
|
linkContent += `<div>${escapeJSX(displayText)}</div>`;
|
|
2009
2018
|
|
|
2010
|
-
links.push(
|
|
2019
|
+
links.push(
|
|
2020
|
+
`${ind(ctx)} <a href="${escapeJSX(path)}"${hreflangAttr}${currentAttr} data-locale="${escapeJSX(code)}"${classAttr}>${linkContent}</a>`,
|
|
2021
|
+
);
|
|
2011
2022
|
}
|
|
2012
2023
|
|
|
2013
2024
|
// Join with separator
|
|
@@ -2023,7 +2034,8 @@ function emitLocaleListNode(node: LocaleListNode, ctx: AstroEmitContext): string
|
|
|
2023
2034
|
|
|
2024
2035
|
return (
|
|
2025
2036
|
`${ind(ctx)}<div data-locale-list="true"${containerClassExpr}${containerStyleAttr}${attrs}>\n` +
|
|
2026
|
-
linksContent +
|
|
2037
|
+
linksContent +
|
|
2038
|
+
'\n' +
|
|
2027
2039
|
`${ind(ctx)}</div>\n`
|
|
2028
2040
|
);
|
|
2029
2041
|
}
|
|
@@ -2072,7 +2084,7 @@ function emitIfOpen(node: ComponentNode, ctx: AstroEmitContext): string {
|
|
|
2072
2084
|
const match = ifValue.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
2073
2085
|
if (match) {
|
|
2074
2086
|
const binding = ctx.cmsEntryBinding || 'entry';
|
|
2075
|
-
return `${ind(ctx)}{${binding}.data.${match[1].trim()} && (\n`;
|
|
2087
|
+
return `${ind(ctx)}{${binding}.data.${(match[1] ?? '').trim()} && (\n`;
|
|
2076
2088
|
}
|
|
2077
2089
|
}
|
|
2078
2090
|
|
|
@@ -2080,7 +2092,7 @@ function emitIfOpen(node: ComponentNode, ctx: AstroEmitContext): string {
|
|
|
2080
2092
|
if (ctx.listItemBinding && /\{\{/.test(ifValue)) {
|
|
2081
2093
|
const match = ifValue.match(/^\{\{([^}]+)\}\}$/);
|
|
2082
2094
|
if (match) {
|
|
2083
|
-
let expr = match[1].trim();
|
|
2095
|
+
let expr = (match[1] ?? '').trim();
|
|
2084
2096
|
expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
2085
2097
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
2086
2098
|
return `${ind(ctx)}{${expr} && (\n`;
|
|
@@ -2094,7 +2106,7 @@ function emitIfOpen(node: ComponentNode, ctx: AstroEmitContext): string {
|
|
|
2094
2106
|
// Plain string without template syntax and not a valid identifier — always truthy, skip conditional
|
|
2095
2107
|
return '';
|
|
2096
2108
|
}
|
|
2097
|
-
let expr = fullMatch ? fullMatch[1].trim() : ifValue.replace(/\{\{(.+?)\}\}/g, '$1');
|
|
2109
|
+
let expr = fullMatch ? (fullMatch[1] ?? '').trim() : ifValue.replace(/\{\{(.+?)\}\}/g, '$1');
|
|
2098
2110
|
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
2099
2111
|
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
2100
2112
|
return `${ind(ctx)}{${expr} && (\n`;
|
|
@@ -2111,6 +2123,10 @@ function emitIfClose(node: ComponentNode, ctx: AstroEmitContext): string {
|
|
|
2111
2123
|
if (typeof ifValue === 'boolean') return '';
|
|
2112
2124
|
|
|
2113
2125
|
if (typeof ifValue === 'object' && ifValue._mapping && ctx.isComponentDef) {
|
|
2126
|
+
// Degenerate mapping (no true values): emitIfOpen emitted only a
|
|
2127
|
+
// `{/* hidden */}` comment, not a `{cond && (` opener — close nothing.
|
|
2128
|
+
const hasTrueValue = Object.values(ifValue.values).some((v) => v === true);
|
|
2129
|
+
if (!hasTrueValue) return '';
|
|
2114
2130
|
return `${ind(ctx)})}\n`;
|
|
2115
2131
|
}
|
|
2116
2132
|
|
|
@@ -2139,7 +2155,7 @@ function emitIfClose(node: ComponentNode, ctx: AstroEmitContext): string {
|
|
|
2139
2155
|
|
|
2140
2156
|
function emitChildren(
|
|
2141
2157
|
children: (ComponentNode | string)[] | string | ComponentNode | null | undefined,
|
|
2142
|
-
ctx: AstroEmitContext
|
|
2158
|
+
ctx: AstroEmitContext,
|
|
2143
2159
|
): string {
|
|
2144
2160
|
if (!children) return '';
|
|
2145
2161
|
|