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
|
@@ -356,17 +356,11 @@ describe('itemTemplateUtils', () => {
|
|
|
356
356
|
|
|
357
357
|
it('should process nested arrays', () => {
|
|
358
358
|
const props = {
|
|
359
|
-
outer: [
|
|
360
|
-
['{{item.title}}', 'static'],
|
|
361
|
-
['{{item.url}}'],
|
|
362
|
-
]
|
|
359
|
+
outer: [['{{item.title}}', 'static'], ['{{item.url}}']],
|
|
363
360
|
};
|
|
364
361
|
const result = processItemPropsTemplate(props, baseContext);
|
|
365
362
|
expect(result).toEqual({
|
|
366
|
-
outer: [
|
|
367
|
-
['Test Title', 'static'],
|
|
368
|
-
['/test-url'],
|
|
369
|
-
]
|
|
363
|
+
outer: [['Test Title', 'static'], ['/test-url']],
|
|
370
364
|
});
|
|
371
365
|
});
|
|
372
366
|
|
|
@@ -375,24 +369,24 @@ describe('itemTemplateUtils', () => {
|
|
|
375
369
|
items: [
|
|
376
370
|
{ label: '{{item.title}}', href: '{{item.url}}' },
|
|
377
371
|
{ label: 'Static', href: '/static' },
|
|
378
|
-
]
|
|
372
|
+
],
|
|
379
373
|
};
|
|
380
374
|
const result = processItemPropsTemplate(props, baseContext);
|
|
381
375
|
expect(result).toEqual({
|
|
382
376
|
items: [
|
|
383
377
|
{ label: 'Test Title', href: '/test-url' },
|
|
384
378
|
{ label: 'Static', href: '/static' },
|
|
385
|
-
]
|
|
379
|
+
],
|
|
386
380
|
});
|
|
387
381
|
});
|
|
388
382
|
|
|
389
383
|
it('should handle mixed array content', () => {
|
|
390
384
|
const props = {
|
|
391
|
-
tags: ['{{item.title}}', 42, true, null, { nested: '{{item.url}}' }]
|
|
385
|
+
tags: ['{{item.title}}', 42, true, null, { nested: '{{item.url}}' }],
|
|
392
386
|
};
|
|
393
387
|
const result = processItemPropsTemplate(props, baseContext);
|
|
394
388
|
expect(result).toEqual({
|
|
395
|
-
tags: ['Test Title', 42, true, null, { nested: '/test-url' }]
|
|
389
|
+
tags: ['Test Title', 42, true, null, { nested: '/test-url' }],
|
|
396
390
|
});
|
|
397
391
|
});
|
|
398
392
|
|
|
@@ -770,16 +764,16 @@ describe('itemTemplateUtils', () => {
|
|
|
770
764
|
];
|
|
771
765
|
const results = addItemUrls(items, schema);
|
|
772
766
|
expect(results).toHaveLength(3);
|
|
773
|
-
expect(results[0]
|
|
774
|
-
expect(results[1]
|
|
775
|
-
expect(results[2]
|
|
767
|
+
expect(results[0]!._url).toBe('/blog/first-post');
|
|
768
|
+
expect(results[1]!._url).toBe('/blog/second-post');
|
|
769
|
+
expect(results[2]!._url).toBe('/blog/third-post');
|
|
776
770
|
});
|
|
777
771
|
|
|
778
772
|
it('should not mutate original items', () => {
|
|
779
773
|
const items: CMSItem[] = [{ _id: '1', slug: 'test' }];
|
|
780
774
|
const results = addItemUrls(items, schema);
|
|
781
|
-
expect(items[0]
|
|
782
|
-
expect(results[0]
|
|
775
|
+
expect(items[0]!._url).toBeUndefined();
|
|
776
|
+
expect(results[0]!._url).toBe('/blog/test');
|
|
783
777
|
});
|
|
784
778
|
|
|
785
779
|
it('should handle empty array', () => {
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
|
|
22
22
|
import type { ItemContext, TemplateContext, CMSItem, CMSSchema } from './types/cms';
|
|
23
23
|
import type { ValueResolver, I18nConfig } from './types/components';
|
|
24
|
-
import { isRichTextMarker, richTextMarkerToHtml } from './propResolver';
|
|
25
24
|
import { safeEvaluate, isComplexExpression } from './expressionEvaluator';
|
|
26
25
|
import { getGlobalTemplateContext } from './globalTemplateContext';
|
|
27
26
|
import { isI18nValue, resolveI18nValue, DEFAULT_I18N_CONFIG } from './i18n';
|
|
@@ -85,7 +84,11 @@ function formatTemplateValue(value: unknown, resolveValue?: ValueResolver): stri
|
|
|
85
84
|
return '';
|
|
86
85
|
}
|
|
87
86
|
// Handle rich-text markers
|
|
88
|
-
if (
|
|
87
|
+
if (
|
|
88
|
+
typeof value === 'object' &&
|
|
89
|
+
'__richtext__' in value &&
|
|
90
|
+
typeof (value as unknown as { html: string }).html === 'string'
|
|
91
|
+
) {
|
|
89
92
|
return (value as unknown as { html: string }).html;
|
|
90
93
|
}
|
|
91
94
|
return String(value);
|
|
@@ -120,10 +123,10 @@ function buildEvalContext(ctx: ItemContext | TemplateContext): Record<string, un
|
|
|
120
123
|
export function processItemTemplate(
|
|
121
124
|
text: string,
|
|
122
125
|
ctx: ItemContext | TemplateContext,
|
|
123
|
-
resolveValue?: ValueResolver
|
|
126
|
+
resolveValue?: ValueResolver,
|
|
124
127
|
): string {
|
|
125
128
|
// Process all {{...}} patterns
|
|
126
|
-
|
|
129
|
+
const result = text.replace(/\{\{([^}]+)\}\}/g, (match, expression) => {
|
|
127
130
|
const trimmed = expression.trim();
|
|
128
131
|
|
|
129
132
|
// Check if this is a complex expression (has operators like ?, :, <, >, etc.)
|
|
@@ -172,11 +175,7 @@ export function processItemTemplate(
|
|
|
172
175
|
* Process named context templates like {{post.title}}, {{postIndex}}, etc.
|
|
173
176
|
* Supports multiple named contexts for nested lists (e.g., post + author).
|
|
174
177
|
*/
|
|
175
|
-
function
|
|
176
|
-
text: string,
|
|
177
|
-
ctx: TemplateContext,
|
|
178
|
-
resolveValue?: ValueResolver
|
|
179
|
-
): string {
|
|
178
|
+
function _processNamedTemplates(text: string, ctx: TemplateContext, resolveValue?: ValueResolver): string {
|
|
180
179
|
let result = text;
|
|
181
180
|
|
|
182
181
|
// Process {{varName.field}} patterns
|
|
@@ -211,13 +210,14 @@ function processNamedTemplates(
|
|
|
211
210
|
function resolveCompleteTemplateRaw(
|
|
212
211
|
template: string,
|
|
213
212
|
ctx: ItemContext | TemplateContext,
|
|
214
|
-
resolveValue?: ValueResolver
|
|
213
|
+
resolveValue?: ValueResolver,
|
|
215
214
|
): unknown {
|
|
216
215
|
// Only handle single complete template expressions like {{varName.field}}
|
|
217
216
|
const match = template.match(/^\{\{(\w+)\.([^}]+)\}\}$/);
|
|
218
217
|
if (!match) return undefined;
|
|
219
218
|
|
|
220
|
-
const
|
|
219
|
+
const varName = match[1] ?? '';
|
|
220
|
+
const fieldPath = match[2] ?? '';
|
|
221
221
|
|
|
222
222
|
// Check for complex expressions (ternary, comparisons, etc.) - not raw-resolvable
|
|
223
223
|
const trimmedField = fieldPath.trim();
|
|
@@ -250,7 +250,7 @@ function resolveCompleteTemplateRaw(
|
|
|
250
250
|
export function processItemPropsTemplate(
|
|
251
251
|
props: Record<string, unknown>,
|
|
252
252
|
ctx: ItemContext | TemplateContext,
|
|
253
|
-
resolveValue?: ValueResolver
|
|
253
|
+
resolveValue?: ValueResolver,
|
|
254
254
|
): Record<string, unknown> {
|
|
255
255
|
const result: Record<string, unknown> = {};
|
|
256
256
|
|
|
@@ -267,7 +267,7 @@ export function processItemPropsTemplate(
|
|
|
267
267
|
}
|
|
268
268
|
} else if (Array.isArray(value)) {
|
|
269
269
|
// Process arrays - recursively handle each element
|
|
270
|
-
result[key] = value.map(item => {
|
|
270
|
+
result[key] = value.map((item) => {
|
|
271
271
|
if (typeof item === 'string' && hasItemTemplates(item)) {
|
|
272
272
|
return processItemTemplate(item, ctx, resolveValue);
|
|
273
273
|
} else if (item && typeof item === 'object' && !Array.isArray(item)) {
|
|
@@ -300,10 +300,7 @@ export function processItemPropsTemplate(
|
|
|
300
300
|
* resolveItemsTemplate("{{post.tagIds}}", { post: { tagIds: ["tag-1", "tag-2"] } })
|
|
301
301
|
* // Returns: ["tag-1", "tag-2"]
|
|
302
302
|
*/
|
|
303
|
-
export function resolveItemsTemplate(
|
|
304
|
-
template: string,
|
|
305
|
-
ctx: TemplateContext
|
|
306
|
-
): string | string[] | undefined {
|
|
303
|
+
export function resolveItemsTemplate(template: string, ctx: TemplateContext): string | string[] | undefined {
|
|
307
304
|
// Match single template expression: {{varName.field}}
|
|
308
305
|
const match = template.match(/^\{\{(\w+)\.([^}]+)\}\}$/);
|
|
309
306
|
if (!match) {
|
|
@@ -311,7 +308,8 @@ export function resolveItemsTemplate(
|
|
|
311
308
|
return template;
|
|
312
309
|
}
|
|
313
310
|
|
|
314
|
-
const
|
|
311
|
+
const varName = match[1] ?? '';
|
|
312
|
+
const fieldPath = match[2] ?? '';
|
|
315
313
|
const item = ctx[varName];
|
|
316
314
|
if (!item || typeof item !== 'object') {
|
|
317
315
|
return undefined;
|
|
@@ -324,7 +322,7 @@ export function resolveItemsTemplate(
|
|
|
324
322
|
|
|
325
323
|
// Return as string or string array
|
|
326
324
|
if (Array.isArray(value)) {
|
|
327
|
-
return value.map(v => String(v));
|
|
325
|
+
return value.map((v) => String(v));
|
|
328
326
|
}
|
|
329
327
|
return String(value);
|
|
330
328
|
}
|
|
@@ -338,15 +336,13 @@ export function resolveItemsTemplate(
|
|
|
338
336
|
* resolveTemplateRawValue("{{article.link}}", { article: { link: { href: "/about", target: "_blank" } } })
|
|
339
337
|
* // Returns: { href: "/about", target: "_blank" }
|
|
340
338
|
*/
|
|
341
|
-
export function resolveTemplateRawValue(
|
|
342
|
-
template: string,
|
|
343
|
-
ctx: TemplateContext
|
|
344
|
-
): unknown {
|
|
339
|
+
export function resolveTemplateRawValue(template: string, ctx: TemplateContext): unknown {
|
|
345
340
|
// Match single template expression: {{varName.field}}
|
|
346
341
|
const match = template.match(/^\{\{(\w+)\.([^}]+)\}\}$/);
|
|
347
342
|
if (!match) return undefined;
|
|
348
343
|
|
|
349
|
-
const
|
|
344
|
+
const varName = match[1] ?? '';
|
|
345
|
+
const fieldPath = match[2] ?? '';
|
|
350
346
|
const item = ctx[varName];
|
|
351
347
|
if (!item || typeof item !== 'object') return undefined;
|
|
352
348
|
|
|
@@ -368,7 +364,7 @@ export function buildTemplateContext(
|
|
|
368
364
|
item: CMSItem,
|
|
369
365
|
index: number,
|
|
370
366
|
total: number,
|
|
371
|
-
parentContext?: TemplateContext
|
|
367
|
+
parentContext?: TemplateContext,
|
|
372
368
|
): TemplateContext {
|
|
373
369
|
const isFirst = index === 0;
|
|
374
370
|
const isLast = index === total - 1;
|
|
@@ -422,7 +418,7 @@ export function buildItemUrl(
|
|
|
422
418
|
item: CMSItem,
|
|
423
419
|
slugField: string,
|
|
424
420
|
locale?: string,
|
|
425
|
-
i18nConfig?: I18nConfig
|
|
421
|
+
i18nConfig?: I18nConfig,
|
|
426
422
|
): string {
|
|
427
423
|
// Get slug from the schema-defined slugField, fall back to _filename, _slug, or _id
|
|
428
424
|
let slug = item[slugField] ?? item._filename ?? item._slug ?? item._id;
|
|
@@ -447,12 +443,9 @@ export function buildItemUrl(
|
|
|
447
443
|
* @param i18nConfig - Optional i18n configuration
|
|
448
444
|
* @returns A new item object with _url computed field added
|
|
449
445
|
*/
|
|
450
|
-
export function addItemUrl(
|
|
451
|
-
item
|
|
452
|
-
schema
|
|
453
|
-
locale?: string,
|
|
454
|
-
i18nConfig?: I18nConfig
|
|
455
|
-
): CMSItem {
|
|
446
|
+
export function addItemUrl(item: CMSItem, schema: CMSSchema, locale?: string, i18nConfig?: I18nConfig): CMSItem {
|
|
447
|
+
// A data-only collection (no urlPattern/slugField) has no per-item URL — leave it off.
|
|
448
|
+
if (!schema.urlPattern || !schema.slugField) return item;
|
|
456
449
|
return {
|
|
457
450
|
...item,
|
|
458
451
|
_url: buildItemUrl(schema.urlPattern, item, schema.slugField, locale, i18nConfig),
|
|
@@ -468,11 +461,6 @@ export function addItemUrl(
|
|
|
468
461
|
* @param i18nConfig - Optional i18n configuration
|
|
469
462
|
* @returns Array of items with _url computed field added
|
|
470
463
|
*/
|
|
471
|
-
export function addItemUrls(
|
|
472
|
-
items
|
|
473
|
-
schema: CMSSchema,
|
|
474
|
-
locale?: string,
|
|
475
|
-
i18nConfig?: I18nConfig
|
|
476
|
-
): CMSItem[] {
|
|
477
|
-
return items.map(item => addItemUrl(item, schema, locale, i18nConfig));
|
|
464
|
+
export function addItemUrls(items: CMSItem[], schema: CMSSchema, locale?: string, i18nConfig?: I18nConfig): CMSItem[] {
|
|
465
|
+
return items.map((item) => addItemUrl(item, schema, locale, i18nConfig));
|
|
478
466
|
}
|
package/lib/shared/jsonRepair.ts
CHANGED
|
@@ -33,7 +33,7 @@ export function parseJsonError(error: unknown, content: string): JsonParseErrorI
|
|
|
33
33
|
// Try to extract position from message
|
|
34
34
|
const posMatch = msg.match(/at position (\d+)/i);
|
|
35
35
|
if (posMatch) {
|
|
36
|
-
const pos = parseInt(posMatch[1], 10);
|
|
36
|
+
const pos = parseInt(posMatch[1] ?? '', 10);
|
|
37
37
|
const { line, column } = offsetToLineColumn(content, pos);
|
|
38
38
|
return { message: msg, line, column };
|
|
39
39
|
}
|
|
@@ -45,8 +45,8 @@ export function parseJsonError(error: unknown, content: string): JsonParseErrorI
|
|
|
45
45
|
if (lineMatch) {
|
|
46
46
|
return {
|
|
47
47
|
message: msg,
|
|
48
|
-
line: parseInt(lineMatch[1], 10),
|
|
49
|
-
column: colMatch ? parseInt(colMatch[1], 10) : 1,
|
|
48
|
+
line: parseInt(lineMatch[1] ?? '', 10),
|
|
49
|
+
column: colMatch ? parseInt(colMatch[1] ?? '', 10) : 1,
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -73,7 +73,7 @@ export function attemptJsonRepair(content: string): JsonRepairResult {
|
|
|
73
73
|
try {
|
|
74
74
|
const data = JSON.parse(content);
|
|
75
75
|
return { success: true, repaired: false, data };
|
|
76
|
-
} catch (
|
|
76
|
+
} catch (_firstError) {
|
|
77
77
|
// Continue to repair attempts
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -108,27 +108,33 @@ export function attemptJsonRepair(content: string): JsonRepairResult {
|
|
|
108
108
|
let repairLine = 0;
|
|
109
109
|
|
|
110
110
|
for (let i = 0; i < lines.length; i++) {
|
|
111
|
-
const line = lines[i];
|
|
111
|
+
const line = lines[i] ?? '';
|
|
112
112
|
const trimmed = line.trimEnd();
|
|
113
|
-
const nextLine = i + 1 < lines.length ? lines[i + 1] : null;
|
|
113
|
+
const nextLine = i + 1 < lines.length ? (lines[i + 1] ?? null) : null;
|
|
114
114
|
|
|
115
115
|
if (nextLine !== null) {
|
|
116
116
|
const nextTrimmed = nextLine.trimStart();
|
|
117
117
|
// Check if current line ends with a value (not comma, not opening bracket, not colon)
|
|
118
118
|
// and next line starts with a key or value
|
|
119
119
|
const needsComma =
|
|
120
|
-
/["\d\w\]}
|
|
120
|
+
/["\d\w\]}-]$/.test(trimmed) &&
|
|
121
121
|
!trimmed.endsWith(',') &&
|
|
122
122
|
!trimmed.endsWith('{') &&
|
|
123
123
|
!trimmed.endsWith('[') &&
|
|
124
124
|
!trimmed.endsWith(':') &&
|
|
125
|
-
(nextTrimmed.startsWith('"') ||
|
|
125
|
+
(nextTrimmed.startsWith('"') ||
|
|
126
|
+
nextTrimmed.startsWith('{') ||
|
|
127
|
+
nextTrimmed.startsWith('[') ||
|
|
128
|
+
/^\d/.test(nextTrimmed) ||
|
|
129
|
+
nextTrimmed === 'true' ||
|
|
130
|
+
nextTrimmed === 'false' ||
|
|
131
|
+
nextTrimmed === 'null');
|
|
126
132
|
|
|
127
133
|
if (needsComma) {
|
|
128
|
-
fixed += trimmed
|
|
134
|
+
fixed += `${trimmed},\n`;
|
|
129
135
|
if (repairLine === 0) repairLine = i + 1;
|
|
130
136
|
} else {
|
|
131
|
-
fixed += line
|
|
137
|
+
fixed += `${line}\n`;
|
|
132
138
|
}
|
|
133
139
|
} else {
|
|
134
140
|
fixed += line;
|
|
@@ -6,12 +6,7 @@ import {
|
|
|
6
6
|
generateLibraryTags,
|
|
7
7
|
extractLibraryOrigins,
|
|
8
8
|
} from './libraryLoader';
|
|
9
|
-
import type {
|
|
10
|
-
JSLibraryConfig,
|
|
11
|
-
CSSLibraryConfig,
|
|
12
|
-
LibrariesConfig,
|
|
13
|
-
PageLibrariesConfig,
|
|
14
|
-
} from './types/libraries';
|
|
9
|
+
import type { JSLibraryConfig, CSSLibraryConfig, LibrariesConfig, PageLibrariesConfig } from './types/libraries';
|
|
15
10
|
|
|
16
11
|
describe('libraryLoader', () => {
|
|
17
12
|
// ---------------------------------------------------------------------------
|
|
@@ -73,12 +68,8 @@ describe('libraryLoader', () => {
|
|
|
73
68
|
css: [{ url: 'https://cdn.example.com/replacement.css' }],
|
|
74
69
|
};
|
|
75
70
|
const result = mergeLibraries(globalLibs, page);
|
|
76
|
-
expect(result.js).toEqual([
|
|
77
|
-
|
|
78
|
-
]);
|
|
79
|
-
expect(result.css).toEqual([
|
|
80
|
-
{ url: 'https://cdn.example.com/replacement.css' },
|
|
81
|
-
]);
|
|
71
|
+
expect(result.js).toEqual([{ url: 'https://cdn.example.com/replacement.js' }]);
|
|
72
|
+
expect(result.css).toEqual([{ url: 'https://cdn.example.com/replacement.css' }]);
|
|
82
73
|
});
|
|
83
74
|
|
|
84
75
|
test('replace mode: defaults to empty arrays when page.js and page.css are missing', () => {
|
|
@@ -129,12 +120,12 @@ describe('libraryLoader', () => {
|
|
|
129
120
|
css: [{ url: 'https://cdn.example.com/b.css', media: 'screen' }],
|
|
130
121
|
};
|
|
131
122
|
const result = mergeLibraries(global, page);
|
|
132
|
-
expect(result.js![0]
|
|
133
|
-
expect(result.js![0]
|
|
134
|
-
expect(result.js![1]
|
|
135
|
-
expect(result.js![1]
|
|
136
|
-
expect(result.css![0]
|
|
137
|
-
expect(result.css![1]
|
|
123
|
+
expect(result.js![0]!.mode).toBe('async');
|
|
124
|
+
expect(result.js![0]!.position).toBe('head');
|
|
125
|
+
expect(result.js![1]!.mode).toBe('defer');
|
|
126
|
+
expect(result.js![1]!.position).toBe('body-end');
|
|
127
|
+
expect(result.css![0]!.media).toBe('print');
|
|
128
|
+
expect(result.css![1]!.media).toBe('screen');
|
|
138
129
|
});
|
|
139
130
|
});
|
|
140
131
|
|
|
@@ -218,9 +209,7 @@ describe('libraryLoader', () => {
|
|
|
218
209
|
test('includes media attribute when provided', () => {
|
|
219
210
|
const lib: CSSLibraryConfig = { url: 'https://cdn.example.com/print.css', media: 'print' };
|
|
220
211
|
const tag = generateStylesheetTag(lib);
|
|
221
|
-
expect(tag).toBe(
|
|
222
|
-
'<link rel="stylesheet" href="https://cdn.example.com/print.css" media="print">'
|
|
223
|
-
);
|
|
212
|
+
expect(tag).toBe('<link rel="stylesheet" href="https://cdn.example.com/print.css" media="print">');
|
|
224
213
|
});
|
|
225
214
|
|
|
226
215
|
test('handles complex media query', () => {
|
|
@@ -278,9 +267,7 @@ describe('libraryLoader', () => {
|
|
|
278
267
|
js: [],
|
|
279
268
|
};
|
|
280
269
|
const tags = generateLibraryTags(libs);
|
|
281
|
-
expect(tags.headCSS).toBe(
|
|
282
|
-
'<link rel="stylesheet" href="https://cdn.example.com/style.css">'
|
|
283
|
-
);
|
|
270
|
+
expect(tags.headCSS).toBe('<link rel="stylesheet" href="https://cdn.example.com/style.css">');
|
|
284
271
|
expect(tags.headJS).toBe('');
|
|
285
272
|
expect(tags.bodyEndJS).toBe('');
|
|
286
273
|
});
|
|
@@ -291,9 +278,7 @@ describe('libraryLoader', () => {
|
|
|
291
278
|
css: [],
|
|
292
279
|
};
|
|
293
280
|
const tags = generateLibraryTags(libs);
|
|
294
|
-
expect(tags.bodyEndJS).toBe(
|
|
295
|
-
'<script src="https://cdn.example.com/lib.js" defer></script>'
|
|
296
|
-
);
|
|
281
|
+
expect(tags.bodyEndJS).toBe('<script src="https://cdn.example.com/lib.js" defer></script>');
|
|
297
282
|
expect(tags.headJS).toBe('');
|
|
298
283
|
expect(tags.headCSS).toBe('');
|
|
299
284
|
});
|
|
@@ -304,9 +289,7 @@ describe('libraryLoader', () => {
|
|
|
304
289
|
css: [],
|
|
305
290
|
};
|
|
306
291
|
const tags = generateLibraryTags(libs);
|
|
307
|
-
expect(tags.headJS).toBe(
|
|
308
|
-
'<script src="https://cdn.example.com/head.js" defer></script>'
|
|
309
|
-
);
|
|
292
|
+
expect(tags.headJS).toBe('<script src="https://cdn.example.com/head.js" defer></script>');
|
|
310
293
|
expect(tags.bodyEndJS).toBe('');
|
|
311
294
|
});
|
|
312
295
|
|
|
@@ -316,9 +299,7 @@ describe('libraryLoader', () => {
|
|
|
316
299
|
css: [],
|
|
317
300
|
};
|
|
318
301
|
const tags = generateLibraryTags(libs);
|
|
319
|
-
expect(tags.bodyEndJS).toBe(
|
|
320
|
-
'<script src="https://cdn.example.com/foot.js" defer></script>'
|
|
321
|
-
);
|
|
302
|
+
expect(tags.bodyEndJS).toBe('<script src="https://cdn.example.com/foot.js" defer></script>');
|
|
322
303
|
expect(tags.headJS).toBe('');
|
|
323
304
|
});
|
|
324
305
|
|
|
@@ -340,31 +321,25 @@ describe('libraryLoader', () => {
|
|
|
340
321
|
|
|
341
322
|
test('multiple CSS libs joined with newline and indentation', () => {
|
|
342
323
|
const libs: LibrariesConfig = {
|
|
343
|
-
css: [
|
|
344
|
-
{ url: 'https://cdn.example.com/a.css' },
|
|
345
|
-
{ url: 'https://cdn.example.com/b.css' },
|
|
346
|
-
],
|
|
324
|
+
css: [{ url: 'https://cdn.example.com/a.css' }, { url: 'https://cdn.example.com/b.css' }],
|
|
347
325
|
js: [],
|
|
348
326
|
};
|
|
349
327
|
const tags = generateLibraryTags(libs);
|
|
350
328
|
expect(tags.headCSS).toBe(
|
|
351
329
|
'<link rel="stylesheet" href="https://cdn.example.com/a.css">\n ' +
|
|
352
|
-
|
|
330
|
+
'<link rel="stylesheet" href="https://cdn.example.com/b.css">',
|
|
353
331
|
);
|
|
354
332
|
});
|
|
355
333
|
|
|
356
334
|
test('multiple JS libs joined with newline and indentation', () => {
|
|
357
335
|
const libs: LibrariesConfig = {
|
|
358
|
-
js: [
|
|
359
|
-
{ url: 'https://cdn.example.com/a.js' },
|
|
360
|
-
{ url: 'https://cdn.example.com/b.js' },
|
|
361
|
-
],
|
|
336
|
+
js: [{ url: 'https://cdn.example.com/a.js' }, { url: 'https://cdn.example.com/b.js' }],
|
|
362
337
|
css: [],
|
|
363
338
|
};
|
|
364
339
|
const tags = generateLibraryTags(libs);
|
|
365
340
|
expect(tags.bodyEndJS).toBe(
|
|
366
341
|
'<script src="https://cdn.example.com/a.js" defer></script>\n ' +
|
|
367
|
-
|
|
342
|
+
'<script src="https://cdn.example.com/b.js" defer></script>',
|
|
368
343
|
);
|
|
369
344
|
});
|
|
370
345
|
|
|
@@ -446,10 +421,7 @@ describe('libraryLoader', () => {
|
|
|
446
421
|
|
|
447
422
|
test('deduplicates origins from same domain', () => {
|
|
448
423
|
const libs: LibrariesConfig = {
|
|
449
|
-
js: [
|
|
450
|
-
{ url: 'https://cdn.jsdelivr.net/npm/lib-a.js' },
|
|
451
|
-
{ url: 'https://cdn.jsdelivr.net/npm/lib-b.js' },
|
|
452
|
-
],
|
|
424
|
+
js: [{ url: 'https://cdn.jsdelivr.net/npm/lib-a.js' }, { url: 'https://cdn.jsdelivr.net/npm/lib-b.js' }],
|
|
453
425
|
css: [],
|
|
454
426
|
};
|
|
455
427
|
const { scriptOrigins } = extractLibraryOrigins(libs);
|
|
@@ -482,14 +454,8 @@ describe('libraryLoader', () => {
|
|
|
482
454
|
|
|
483
455
|
test('handles multiple different domains', () => {
|
|
484
456
|
const libs: LibrariesConfig = {
|
|
485
|
-
js: [
|
|
486
|
-
|
|
487
|
-
{ url: 'https://unpkg.com/other-lib.js' },
|
|
488
|
-
],
|
|
489
|
-
css: [
|
|
490
|
-
{ url: 'https://fonts.googleapis.com/css' },
|
|
491
|
-
{ url: 'https://cdn.jsdelivr.net/npm/style.css' },
|
|
492
|
-
],
|
|
457
|
+
js: [{ url: 'https://cdn.jsdelivr.net/npm/lib.js' }, { url: 'https://unpkg.com/other-lib.js' }],
|
|
458
|
+
css: [{ url: 'https://fonts.googleapis.com/css' }, { url: 'https://cdn.jsdelivr.net/npm/style.css' }],
|
|
493
459
|
};
|
|
494
460
|
const { scriptOrigins, styleOrigins } = extractLibraryOrigins(libs);
|
|
495
461
|
expect(scriptOrigins.size).toBe(2);
|
|
@@ -3,23 +3,14 @@
|
|
|
3
3
|
* Generates HTML tags for external JS/CSS libraries
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
7
|
-
JSLibraryConfig,
|
|
8
|
-
CSSLibraryConfig,
|
|
9
|
-
LibrariesConfig,
|
|
10
|
-
PageLibrariesConfig,
|
|
11
|
-
} from './types/libraries';
|
|
6
|
+
import type { JSLibraryConfig, CSSLibraryConfig, LibrariesConfig, PageLibrariesConfig } from './types/libraries';
|
|
12
7
|
import type { ComponentDefinition } from './types/components';
|
|
13
8
|
|
|
14
9
|
/**
|
|
15
10
|
* Escape HTML special characters in attribute values
|
|
16
11
|
*/
|
|
17
12
|
function escapeAttr(str: string): string {
|
|
18
|
-
return str
|
|
19
|
-
.replace(/&/g, '&')
|
|
20
|
-
.replace(/"/g, '"')
|
|
21
|
-
.replace(/</g, '<')
|
|
22
|
-
.replace(/>/g, '>');
|
|
13
|
+
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
23
14
|
}
|
|
24
15
|
|
|
25
16
|
/**
|
|
@@ -28,10 +19,7 @@ function escapeAttr(str: string): string {
|
|
|
28
19
|
* @param page Page-level libraries from page meta
|
|
29
20
|
* @returns Merged library configuration
|
|
30
21
|
*/
|
|
31
|
-
export function mergeLibraries(
|
|
32
|
-
global: LibrariesConfig,
|
|
33
|
-
page?: PageLibrariesConfig
|
|
34
|
-
): LibrariesConfig {
|
|
22
|
+
export function mergeLibraries(global: LibrariesConfig, page?: PageLibrariesConfig): LibrariesConfig {
|
|
35
23
|
if (!page) {
|
|
36
24
|
return global;
|
|
37
25
|
}
|
|
@@ -86,10 +74,7 @@ export function generateInlineStyleTag(content: string, media?: string): string
|
|
|
86
74
|
* @returns HTML link tag string
|
|
87
75
|
*/
|
|
88
76
|
export function generateStylesheetTag(lib: CSSLibraryConfig): string {
|
|
89
|
-
const attrs: string[] = [
|
|
90
|
-
'rel="stylesheet"',
|
|
91
|
-
`href="${escapeAttr(lib.url)}"`,
|
|
92
|
-
];
|
|
77
|
+
const attrs: string[] = ['rel="stylesheet"', `href="${escapeAttr(lib.url)}"`];
|
|
93
78
|
|
|
94
79
|
if (lib.media) {
|
|
95
80
|
attrs.push(`media="${escapeAttr(lib.media)}"`);
|
|
@@ -157,7 +142,7 @@ export function generateLibraryTags(libs: LibrariesConfig, inlineContents?: Map<
|
|
|
157
142
|
*/
|
|
158
143
|
export function collectComponentLibraries(
|
|
159
144
|
globalComponents: Record<string, ComponentDefinition> = {},
|
|
160
|
-
pageComponents: Record<string, ComponentDefinition> = {}
|
|
145
|
+
pageComponents: Record<string, ComponentDefinition> = {},
|
|
161
146
|
): LibrariesConfig {
|
|
162
147
|
const seenJS = new Set<string>();
|
|
163
148
|
const seenCSS = new Set<string>();
|
|
@@ -230,13 +215,13 @@ export function extractLibraryOrigins(libs: LibrariesConfig): LibraryOrigins {
|
|
|
230
215
|
*/
|
|
231
216
|
export function filterLibrariesByContext(
|
|
232
217
|
libs: LibrariesConfig,
|
|
233
|
-
context: 'editor' | 'build' | 'preview'
|
|
218
|
+
context: 'editor' | 'build' | 'preview',
|
|
234
219
|
): LibrariesConfig {
|
|
235
220
|
if (context === 'preview') return libs;
|
|
236
221
|
const key = context === 'editor' ? 'disableEditor' : 'disableBuild';
|
|
237
222
|
return {
|
|
238
223
|
js: libs.js,
|
|
239
|
-
css: (libs.css || []).filter(css => !css[key]),
|
|
224
|
+
css: (libs.css || []).filter((css) => !css[key]),
|
|
240
225
|
};
|
|
241
226
|
}
|
|
242
227
|
|
package/lib/shared/linkUtils.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Normalize a URL path for comparison (strip trailing slash, query string, hash)
|
|
8
8
|
*/
|
|
9
9
|
export function normalizePath(path: string): string {
|
|
10
|
-
let normalized = path.split('?')[0].split('#')[0];
|
|
10
|
+
let normalized = (path.split('?')[0] ?? '').split('#')[0] ?? '';
|
|
11
11
|
if (normalized.length > 1 && normalized.endsWith('/')) {
|
|
12
12
|
normalized = normalized.slice(0, -1);
|
|
13
13
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { test, expect, describe, afterEach, mock } from 'bun:test';
|
|
2
|
+
import { createLogger, setLogLevel, getLogLevel, setLogSink, type LogRecord } from './logger';
|
|
3
|
+
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
setLogSink(null);
|
|
6
|
+
setLogLevel('debug');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe('logger — level gating', () => {
|
|
10
|
+
test('suppresses levels below the active threshold', () => {
|
|
11
|
+
const records: LogRecord[] = [];
|
|
12
|
+
setLogSink((r) => records.push(r));
|
|
13
|
+
setLogLevel('warn');
|
|
14
|
+
const log = createLogger('Test');
|
|
15
|
+
log.debug('d');
|
|
16
|
+
log.info('i');
|
|
17
|
+
log.warn('w');
|
|
18
|
+
log.error('e');
|
|
19
|
+
expect(records.map((r) => r.level)).toEqual(['warn', 'error']);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('silent suppresses everything', () => {
|
|
23
|
+
const records: LogRecord[] = [];
|
|
24
|
+
setLogSink((r) => records.push(r));
|
|
25
|
+
setLogLevel('silent');
|
|
26
|
+
const log = createLogger();
|
|
27
|
+
log.error('nope');
|
|
28
|
+
expect(records).toHaveLength(0);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('logger — scope + sink', () => {
|
|
33
|
+
test('forwards scope, message, and args to the sink', () => {
|
|
34
|
+
const records: LogRecord[] = [];
|
|
35
|
+
setLogSink((r) => records.push(r));
|
|
36
|
+
setLogLevel('debug');
|
|
37
|
+
createLogger('Area').info('hello', 1, { a: 2 });
|
|
38
|
+
expect(records).toHaveLength(1);
|
|
39
|
+
expect(records[0]).toMatchObject({ level: 'info', scope: 'Area', message: 'hello', args: [1, { a: 2 }] });
|
|
40
|
+
expect(typeof records[0]!.timestamp).toBe('number');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('child nests the scope', () => {
|
|
44
|
+
const records: LogRecord[] = [];
|
|
45
|
+
setLogSink((r) => records.push(r));
|
|
46
|
+
createLogger('Parent').child('Child').warn('x');
|
|
47
|
+
expect(records[0]!.scope).toBe('Parent:Child');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('routes to the matching console method', () => {
|
|
51
|
+
const spy = mock(() => {});
|
|
52
|
+
const orig = console.warn;
|
|
53
|
+
console.warn = spy as unknown as typeof console.warn;
|
|
54
|
+
try {
|
|
55
|
+
createLogger('S').warn('msg');
|
|
56
|
+
} finally {
|
|
57
|
+
console.warn = orig;
|
|
58
|
+
}
|
|
59
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('getLogLevel reflects setLogLevel', () => {
|
|
63
|
+
setLogLevel('info');
|
|
64
|
+
expect(getLogLevel()).toBe('info');
|
|
65
|
+
});
|
|
66
|
+
});
|