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
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
* Tests for generating unique CSS class names for elements in pages and components
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { test, expect, describe } from
|
|
6
|
+
import { test, expect, describe } from 'bun:test';
|
|
7
7
|
import {
|
|
8
8
|
generateElementClassName,
|
|
9
9
|
isElementClassName,
|
|
10
10
|
parseElementClassName,
|
|
11
11
|
type ElementClassContext,
|
|
12
|
-
} from
|
|
12
|
+
} from './elementClassName';
|
|
13
13
|
|
|
14
|
-
describe(
|
|
15
|
-
describe(
|
|
16
|
-
test(
|
|
14
|
+
describe('generateElementClassName', () => {
|
|
15
|
+
describe('Page elements', () => {
|
|
16
|
+
test('should generate page class with p_ prefix', () => {
|
|
17
17
|
const ctx: ElementClassContext = {
|
|
18
|
-
fileType:
|
|
19
|
-
fileName:
|
|
18
|
+
fileType: 'page',
|
|
19
|
+
fileName: 'about',
|
|
20
20
|
path: [0],
|
|
21
21
|
};
|
|
22
22
|
|
|
@@ -25,10 +25,10 @@ describe("generateElementClassName", () => {
|
|
|
25
25
|
expect(className).toMatch(/^p_about_/);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
test(
|
|
28
|
+
test('should generate consistent hash for same path', () => {
|
|
29
29
|
const ctx: ElementClassContext = {
|
|
30
|
-
fileType:
|
|
31
|
-
fileName:
|
|
30
|
+
fileType: 'page',
|
|
31
|
+
fileName: 'about',
|
|
32
32
|
path: [0, 1, 2],
|
|
33
33
|
};
|
|
34
34
|
|
|
@@ -38,16 +38,16 @@ describe("generateElementClassName", () => {
|
|
|
38
38
|
expect(className1).toBe(className2);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
test(
|
|
41
|
+
test('should generate different hashes for different paths', () => {
|
|
42
42
|
// Use significantly different paths to avoid hash collisions
|
|
43
43
|
const ctx1: ElementClassContext = {
|
|
44
|
-
fileType:
|
|
45
|
-
fileName:
|
|
44
|
+
fileType: 'page',
|
|
45
|
+
fileName: 'about',
|
|
46
46
|
path: [0],
|
|
47
47
|
};
|
|
48
48
|
const ctx2: ElementClassContext = {
|
|
49
|
-
fileType:
|
|
50
|
-
fileName:
|
|
49
|
+
fileType: 'page',
|
|
50
|
+
fileName: 'about',
|
|
51
51
|
path: [0, 1, 2, 3],
|
|
52
52
|
};
|
|
53
53
|
|
|
@@ -57,36 +57,36 @@ describe("generateElementClassName", () => {
|
|
|
57
57
|
expect(className1).not.toBe(className2);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
test(
|
|
60
|
+
test('should use label when provided', () => {
|
|
61
61
|
const ctx: ElementClassContext = {
|
|
62
|
-
fileType:
|
|
63
|
-
fileName:
|
|
64
|
-
label:
|
|
62
|
+
fileType: 'page',
|
|
63
|
+
fileName: 'about',
|
|
64
|
+
label: 'header',
|
|
65
65
|
path: [0],
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
const className = generateElementClassName(ctx);
|
|
69
69
|
|
|
70
|
-
expect(className).toBe(
|
|
70
|
+
expect(className).toBe('p_about_header');
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test(
|
|
73
|
+
test('should sanitize label', () => {
|
|
74
74
|
const ctx: ElementClassContext = {
|
|
75
|
-
fileType:
|
|
76
|
-
fileName:
|
|
77
|
-
label:
|
|
75
|
+
fileType: 'page',
|
|
76
|
+
fileName: 'about',
|
|
77
|
+
label: 'My Header Component',
|
|
78
78
|
path: [0],
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
const className = generateElementClassName(ctx);
|
|
82
82
|
|
|
83
|
-
expect(className).toBe(
|
|
83
|
+
expect(className).toBe('p_about_my_header_component');
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
test(
|
|
86
|
+
test('should handle index page path', () => {
|
|
87
87
|
const ctx: ElementClassContext = {
|
|
88
|
-
fileType:
|
|
89
|
-
fileName:
|
|
88
|
+
fileType: 'page',
|
|
89
|
+
fileName: 'index',
|
|
90
90
|
path: [0],
|
|
91
91
|
};
|
|
92
92
|
|
|
@@ -95,10 +95,10 @@ describe("generateElementClassName", () => {
|
|
|
95
95
|
expect(className).toMatch(/^p_index_/);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
test(
|
|
98
|
+
test('should handle nested page paths', () => {
|
|
99
99
|
const ctx: ElementClassContext = {
|
|
100
|
-
fileType:
|
|
101
|
-
fileName:
|
|
100
|
+
fileType: 'page',
|
|
101
|
+
fileName: 'blog_post',
|
|
102
102
|
path: [0, 1, 2],
|
|
103
103
|
};
|
|
104
104
|
|
|
@@ -108,11 +108,11 @@ describe("generateElementClassName", () => {
|
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
describe(
|
|
112
|
-
test(
|
|
111
|
+
describe('Component elements', () => {
|
|
112
|
+
test('should generate component class with c_ prefix', () => {
|
|
113
113
|
const ctx: ElementClassContext = {
|
|
114
|
-
fileType:
|
|
115
|
-
fileName:
|
|
114
|
+
fileType: 'component',
|
|
115
|
+
fileName: 'Navigation',
|
|
116
116
|
path: [0],
|
|
117
117
|
};
|
|
118
118
|
|
|
@@ -121,23 +121,23 @@ describe("generateElementClassName", () => {
|
|
|
121
121
|
expect(className).toMatch(/^c_navigation_/);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
test(
|
|
124
|
+
test('should use label for named elements', () => {
|
|
125
125
|
const ctx: ElementClassContext = {
|
|
126
|
-
fileType:
|
|
127
|
-
fileName:
|
|
128
|
-
label:
|
|
126
|
+
fileType: 'component',
|
|
127
|
+
fileName: 'Navigation',
|
|
128
|
+
label: 'hamburger',
|
|
129
129
|
path: [0],
|
|
130
130
|
};
|
|
131
131
|
|
|
132
132
|
const className = generateElementClassName(ctx);
|
|
133
133
|
|
|
134
|
-
expect(className).toBe(
|
|
134
|
+
expect(className).toBe('c_navigation_hamburger');
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
test(
|
|
137
|
+
test('should generate consistent hash for same component path', () => {
|
|
138
138
|
const ctx: ElementClassContext = {
|
|
139
|
-
fileType:
|
|
140
|
-
fileName:
|
|
139
|
+
fileType: 'component',
|
|
140
|
+
fileName: 'Card',
|
|
141
141
|
path: [0, 0],
|
|
142
142
|
};
|
|
143
143
|
|
|
@@ -147,15 +147,15 @@ describe("generateElementClassName", () => {
|
|
|
147
147
|
expect(className1).toBe(className2);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
-
test(
|
|
150
|
+
test('should generate different hash for different component paths', () => {
|
|
151
151
|
const ctx1: ElementClassContext = {
|
|
152
|
-
fileType:
|
|
153
|
-
fileName:
|
|
152
|
+
fileType: 'component',
|
|
153
|
+
fileName: 'Card',
|
|
154
154
|
path: [0],
|
|
155
155
|
};
|
|
156
156
|
const ctx2: ElementClassContext = {
|
|
157
|
-
fileType:
|
|
158
|
-
fileName:
|
|
157
|
+
fileType: 'component',
|
|
158
|
+
fileName: 'Card',
|
|
159
159
|
path: [0, 0],
|
|
160
160
|
};
|
|
161
161
|
|
|
@@ -165,23 +165,23 @@ describe("generateElementClassName", () => {
|
|
|
165
165
|
expect(className1).not.toBe(className2);
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
-
test(
|
|
168
|
+
test('should generate different hashes for sibling paths (only last index differs)', () => {
|
|
169
169
|
// Regression: a 5-char hash truncated from the high-order digits
|
|
170
170
|
// collapsed to one value when only the final path index changed,
|
|
171
171
|
// making every set of siblings share a class in the Webflow export.
|
|
172
|
-
const base = [
|
|
172
|
+
const base = ['Layout', [0, 0, 1, 0, 0]] as const;
|
|
173
173
|
const siblings = [0, 1, 2, 3, 4].map((i) =>
|
|
174
174
|
generateElementClassName({
|
|
175
|
-
fileType:
|
|
175
|
+
fileType: 'component',
|
|
176
176
|
fileName: base[0],
|
|
177
177
|
path: [...base[1], i],
|
|
178
|
-
})
|
|
178
|
+
}),
|
|
179
179
|
);
|
|
180
180
|
expect(new Set(siblings).size).toBe(siblings.length);
|
|
181
181
|
});
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
-
describe(
|
|
184
|
+
describe('Component-relative paths', () => {
|
|
185
185
|
/**
|
|
186
186
|
* When a component is placed on a page at path [0, 2, 1],
|
|
187
187
|
* its internal elements should use relative paths from the component root.
|
|
@@ -189,17 +189,17 @@ describe("generateElementClassName", () => {
|
|
|
189
189
|
* This ensures the same class is generated regardless of where the component
|
|
190
190
|
* is placed on the page.
|
|
191
191
|
*/
|
|
192
|
-
test(
|
|
192
|
+
test('should generate same class for component elements regardless of page position', () => {
|
|
193
193
|
// Component element at path [0] relative to component root
|
|
194
194
|
const ctx1: ElementClassContext = {
|
|
195
|
-
fileType:
|
|
196
|
-
fileName:
|
|
195
|
+
fileType: 'component',
|
|
196
|
+
fileName: 'Card',
|
|
197
197
|
path: [0], // Relative path within component
|
|
198
198
|
};
|
|
199
199
|
|
|
200
200
|
const ctx2: ElementClassContext = {
|
|
201
|
-
fileType:
|
|
202
|
-
fileName:
|
|
201
|
+
fileType: 'component',
|
|
202
|
+
fileName: 'Card',
|
|
203
203
|
path: [0], // Same relative path
|
|
204
204
|
};
|
|
205
205
|
|
|
@@ -211,16 +211,16 @@ describe("generateElementClassName", () => {
|
|
|
211
211
|
expect(className1).toBe(className2);
|
|
212
212
|
});
|
|
213
213
|
|
|
214
|
-
test(
|
|
214
|
+
test('should generate unique classes for different component names with same path', () => {
|
|
215
215
|
const ctx1: ElementClassContext = {
|
|
216
|
-
fileType:
|
|
217
|
-
fileName:
|
|
216
|
+
fileType: 'component',
|
|
217
|
+
fileName: 'Card',
|
|
218
218
|
path: [0],
|
|
219
219
|
};
|
|
220
220
|
|
|
221
221
|
const ctx2: ElementClassContext = {
|
|
222
|
-
fileType:
|
|
223
|
-
fileName:
|
|
222
|
+
fileType: 'component',
|
|
223
|
+
fileName: 'Button',
|
|
224
224
|
path: [0],
|
|
225
225
|
};
|
|
226
226
|
|
|
@@ -233,11 +233,11 @@ describe("generateElementClassName", () => {
|
|
|
233
233
|
});
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
-
describe(
|
|
237
|
-
test(
|
|
236
|
+
describe('Edge cases', () => {
|
|
237
|
+
test('should handle empty path array', () => {
|
|
238
238
|
const ctx: ElementClassContext = {
|
|
239
|
-
fileType:
|
|
240
|
-
fileName:
|
|
239
|
+
fileType: 'page',
|
|
240
|
+
fileName: 'about',
|
|
241
241
|
path: [],
|
|
242
242
|
};
|
|
243
243
|
|
|
@@ -246,10 +246,10 @@ describe("generateElementClassName", () => {
|
|
|
246
246
|
expect(className).toMatch(/^p_about_/);
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
-
test(
|
|
249
|
+
test('should handle deeply nested paths', () => {
|
|
250
250
|
const ctx: ElementClassContext = {
|
|
251
|
-
fileType:
|
|
252
|
-
fileName:
|
|
251
|
+
fileType: 'page',
|
|
252
|
+
fileName: 'index',
|
|
253
253
|
path: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
254
254
|
};
|
|
255
255
|
|
|
@@ -258,77 +258,77 @@ describe("generateElementClassName", () => {
|
|
|
258
258
|
expect(className).toMatch(/^p_index_/);
|
|
259
259
|
});
|
|
260
260
|
|
|
261
|
-
test(
|
|
261
|
+
test('should handle special characters in fileName', () => {
|
|
262
262
|
const ctx: ElementClassContext = {
|
|
263
|
-
fileType:
|
|
264
|
-
fileName:
|
|
263
|
+
fileType: 'page',
|
|
264
|
+
fileName: 'My Page (v2)',
|
|
265
265
|
path: [0],
|
|
266
266
|
};
|
|
267
267
|
|
|
268
268
|
const className = generateElementClassName(ctx);
|
|
269
269
|
|
|
270
270
|
// Should sanitize special characters
|
|
271
|
-
expect(className).not.toContain(
|
|
272
|
-
expect(className).not.toContain(
|
|
273
|
-
expect(className).not.toContain(
|
|
271
|
+
expect(className).not.toContain('(');
|
|
272
|
+
expect(className).not.toContain(')');
|
|
273
|
+
expect(className).not.toContain(' ');
|
|
274
274
|
});
|
|
275
275
|
});
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
-
describe(
|
|
279
|
-
test(
|
|
280
|
-
expect(isElementClassName(
|
|
281
|
-
expect(isElementClassName(
|
|
278
|
+
describe('isElementClassName', () => {
|
|
279
|
+
test('should return true for valid page class', () => {
|
|
280
|
+
expect(isElementClassName('p_about_header')).toBe(true);
|
|
281
|
+
expect(isElementClassName('p_index_a42e3')).toBe(true);
|
|
282
282
|
});
|
|
283
283
|
|
|
284
|
-
test(
|
|
285
|
-
expect(isElementClassName(
|
|
286
|
-
expect(isElementClassName(
|
|
284
|
+
test('should return true for valid component class', () => {
|
|
285
|
+
expect(isElementClassName('c_navigation_hamburger')).toBe(true);
|
|
286
|
+
expect(isElementClassName('c_card_b12f4')).toBe(true);
|
|
287
287
|
});
|
|
288
288
|
|
|
289
|
-
test(
|
|
290
|
-
expect(isElementClassName(
|
|
291
|
-
expect(isElementClassName(
|
|
292
|
-
expect(isElementClassName(
|
|
293
|
-
expect(isElementClassName(
|
|
294
|
-
expect(isElementClassName(
|
|
289
|
+
test('should return false for invalid classes', () => {
|
|
290
|
+
expect(isElementClassName('about_header')).toBe(false); // Missing prefix
|
|
291
|
+
expect(isElementClassName('p_about')).toBe(false); // Missing element name
|
|
292
|
+
expect(isElementClassName('x_about_header')).toBe(false); // Wrong prefix
|
|
293
|
+
expect(isElementClassName('flex')).toBe(false); // Utility class
|
|
294
|
+
expect(isElementClassName('p-[10px]')).toBe(false); // Utility class
|
|
295
295
|
});
|
|
296
296
|
});
|
|
297
297
|
|
|
298
|
-
describe(
|
|
299
|
-
test(
|
|
300
|
-
const result = parseElementClassName(
|
|
298
|
+
describe('parseElementClassName', () => {
|
|
299
|
+
test('should parse page class correctly', () => {
|
|
300
|
+
const result = parseElementClassName('p_about_header');
|
|
301
301
|
|
|
302
302
|
expect(result).toEqual({
|
|
303
|
-
fileType:
|
|
304
|
-
fileName:
|
|
305
|
-
elementName:
|
|
303
|
+
fileType: 'page',
|
|
304
|
+
fileName: 'about',
|
|
305
|
+
elementName: 'header',
|
|
306
306
|
});
|
|
307
307
|
});
|
|
308
308
|
|
|
309
|
-
test(
|
|
310
|
-
const result = parseElementClassName(
|
|
309
|
+
test('should parse component class correctly', () => {
|
|
310
|
+
const result = parseElementClassName('c_navigation_hamburger');
|
|
311
311
|
|
|
312
312
|
expect(result).toEqual({
|
|
313
|
-
fileType:
|
|
314
|
-
fileName:
|
|
315
|
-
elementName:
|
|
313
|
+
fileType: 'component',
|
|
314
|
+
fileName: 'navigation',
|
|
315
|
+
elementName: 'hamburger',
|
|
316
316
|
});
|
|
317
317
|
});
|
|
318
318
|
|
|
319
|
-
test(
|
|
320
|
-
const result = parseElementClassName(
|
|
319
|
+
test('should parse class with hash correctly', () => {
|
|
320
|
+
const result = parseElementClassName('p_index_a42e3');
|
|
321
321
|
|
|
322
322
|
expect(result).toEqual({
|
|
323
|
-
fileType:
|
|
324
|
-
fileName:
|
|
325
|
-
elementName:
|
|
323
|
+
fileType: 'page',
|
|
324
|
+
fileName: 'index',
|
|
325
|
+
elementName: 'a42e3',
|
|
326
326
|
});
|
|
327
327
|
});
|
|
328
328
|
|
|
329
|
-
test(
|
|
330
|
-
expect(parseElementClassName(
|
|
331
|
-
expect(parseElementClassName(
|
|
332
|
-
expect(parseElementClassName(
|
|
329
|
+
test('should return null for invalid classes', () => {
|
|
330
|
+
expect(parseElementClassName('about_header')).toBeNull();
|
|
331
|
+
expect(parseElementClassName('p_about')).toBeNull();
|
|
332
|
+
expect(parseElementClassName('flex')).toBeNull();
|
|
333
333
|
});
|
|
334
334
|
});
|
|
@@ -93,14 +93,14 @@ export function isElementClassName(className: string): boolean {
|
|
|
93
93
|
* Returns null if not a valid element class name
|
|
94
94
|
*/
|
|
95
95
|
export function parseElementClassName(
|
|
96
|
-
className: string
|
|
96
|
+
className: string,
|
|
97
97
|
): { fileType: 'component' | 'page'; fileName: string; elementName: string } | null {
|
|
98
98
|
const match = className.match(/^([cp])_([a-z0-9_-]+)_([a-z0-9_-]+)$/);
|
|
99
99
|
if (!match) return null;
|
|
100
100
|
|
|
101
101
|
return {
|
|
102
102
|
fileType: match[1] === 'c' ? 'component' : 'page',
|
|
103
|
-
fileName: match[2],
|
|
104
|
-
elementName: match[3],
|
|
103
|
+
fileName: match[2] ?? '',
|
|
104
|
+
elementName: match[3] ?? '',
|
|
105
105
|
};
|
|
106
106
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Find an element with data-element-path attribute by traversing up the DOM tree
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
9
|
* @param element - Starting element to search from
|
|
10
10
|
* @returns Element with data-element-path attribute, or null if not found
|
|
11
11
|
*/
|
|
@@ -25,41 +25,41 @@ export function findElementWithPath(element: HTMLElement | null): HTMLElement |
|
|
|
25
25
|
* The component root is the topmost element (walking up) that:
|
|
26
26
|
* 1. Has data-element-path (is selectable in the tree)
|
|
27
27
|
* 2. Has data-parent-component matching the starting element's component
|
|
28
|
-
*
|
|
28
|
+
*
|
|
29
29
|
* @param element - Starting element (should have data-parent-component attribute)
|
|
30
30
|
* @returns Component instance root element, or null if not found
|
|
31
31
|
*/
|
|
32
32
|
export function findComponentInstanceRoot(element: HTMLElement): HTMLElement | null {
|
|
33
33
|
const componentName = element.getAttribute('data-parent-component');
|
|
34
34
|
if (!componentName) return null;
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
let current: HTMLElement | null = element;
|
|
37
37
|
let componentRoot: HTMLElement | null = null;
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
// Walk up the DOM tree
|
|
40
40
|
while (current) {
|
|
41
41
|
const currentComponentName = current.getAttribute('data-parent-component');
|
|
42
42
|
const hasPath = current.hasAttribute('data-element-path');
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
// If this element has the same component name and has a path, remember it
|
|
45
45
|
// We want the LAST (topmost) one we encounter while still in the component
|
|
46
46
|
if (currentComponentName === componentName && hasPath) {
|
|
47
47
|
componentRoot = current;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
// Stop if we've moved to a different component
|
|
51
51
|
if (currentComponentName && currentComponentName !== componentName) {
|
|
52
52
|
break;
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
// If we've exited the component (no data-parent-component) and we found a root, stop
|
|
56
56
|
if (!currentComponentName && componentRoot) {
|
|
57
57
|
break;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
current = current.parentElement;
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
return componentRoot;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -67,13 +67,13 @@ export function findComponentInstanceRoot(element: HTMLElement): HTMLElement | n
|
|
|
67
67
|
* Alternative implementation: Find component root by walking up until we find
|
|
68
68
|
* an element without data-parent-component (the component root)
|
|
69
69
|
* This is used by elementHighlighter.ts
|
|
70
|
-
*
|
|
70
|
+
*
|
|
71
71
|
* @param element - Starting element
|
|
72
72
|
* @returns Component instance root element, or null if not found
|
|
73
73
|
*/
|
|
74
74
|
export function findComponentInstanceRootByParent(element: HTMLElement): HTMLElement | null {
|
|
75
75
|
let current: HTMLElement | null = element;
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
// Walk up until we find an element without data-parent-component (the component root)
|
|
78
78
|
while (current) {
|
|
79
79
|
if (!current.hasAttribute('data-parent-component')) {
|
|
@@ -81,10 +81,6 @@ export function findComponentInstanceRootByParent(element: HTMLElement): HTMLEle
|
|
|
81
81
|
}
|
|
82
82
|
current = current.parentElement;
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
@@ -19,47 +19,47 @@ describe('logRuntimeError', () => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
test('calls custom handler when set', () => {
|
|
22
|
-
const handler = mock((
|
|
22
|
+
const handler = mock((_entry: ErrorLogEntry) => {});
|
|
23
23
|
setErrorHandler(handler);
|
|
24
24
|
|
|
25
25
|
logRuntimeError('test.location', new Error('test'));
|
|
26
26
|
|
|
27
27
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
28
|
-
const entry = (handler.mock.calls as [ErrorLogEntry][])[0][0];
|
|
28
|
+
const entry = (handler.mock.calls as [ErrorLogEntry][])[0]![0];
|
|
29
29
|
expect(entry.location).toBe('test.location');
|
|
30
30
|
expect(entry.category).toBe('runtime');
|
|
31
31
|
expect(entry.error).toBeInstanceOf(Error);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
test('includes context in handler call', () => {
|
|
35
|
-
const handler = mock((
|
|
35
|
+
const handler = mock((_entry: ErrorLogEntry) => {});
|
|
36
36
|
setErrorHandler(handler);
|
|
37
37
|
|
|
38
38
|
logRuntimeError('test.location', new Error('test'), { extra: 'data' });
|
|
39
39
|
|
|
40
|
-
const entry = (handler.mock.calls as [ErrorLogEntry][])[0][0];
|
|
40
|
+
const entry = (handler.mock.calls as [ErrorLogEntry][])[0]![0];
|
|
41
41
|
expect(entry.context).toEqual({ extra: 'data' });
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
test('includes timestamp in entry', () => {
|
|
45
|
-
const handler = mock((
|
|
45
|
+
const handler = mock((_entry: ErrorLogEntry) => {});
|
|
46
46
|
setErrorHandler(handler);
|
|
47
47
|
const beforeTime = Date.now();
|
|
48
48
|
|
|
49
49
|
logRuntimeError('test.location', new Error('test'));
|
|
50
50
|
|
|
51
|
-
const entry = (handler.mock.calls as [ErrorLogEntry][])[0][0];
|
|
51
|
+
const entry = (handler.mock.calls as [ErrorLogEntry][])[0]![0];
|
|
52
52
|
expect(entry.timestamp).toBeGreaterThanOrEqual(beforeTime);
|
|
53
53
|
expect(entry.timestamp).toBeLessThanOrEqual(Date.now());
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
test('handles string errors', () => {
|
|
57
|
-
const handler = mock((
|
|
57
|
+
const handler = mock((_entry: ErrorLogEntry) => {});
|
|
58
58
|
setErrorHandler(handler);
|
|
59
59
|
|
|
60
60
|
logRuntimeError('test.location', 'string error');
|
|
61
61
|
|
|
62
|
-
const entry = (handler.mock.calls as [ErrorLogEntry][])[0][0];
|
|
62
|
+
const entry = (handler.mock.calls as [ErrorLogEntry][])[0]![0];
|
|
63
63
|
expect(entry.error).toBe('string error');
|
|
64
64
|
});
|
|
65
65
|
|
|
@@ -76,24 +76,24 @@ describe('logNetworkError', () => {
|
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
test('calls custom handler with network category', () => {
|
|
79
|
-
const handler = mock((
|
|
79
|
+
const handler = mock((_entry: ErrorLogEntry) => {});
|
|
80
80
|
setErrorHandler(handler);
|
|
81
81
|
|
|
82
82
|
logNetworkError('api.fetch', new Error('network failed'));
|
|
83
83
|
|
|
84
84
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
85
|
-
const entry = (handler.mock.calls as [ErrorLogEntry][])[0][0];
|
|
85
|
+
const entry = (handler.mock.calls as [ErrorLogEntry][])[0]![0];
|
|
86
86
|
expect(entry.location).toBe('api.fetch');
|
|
87
87
|
expect(entry.category).toBe('network');
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
test('includes context in handler call', () => {
|
|
91
|
-
const handler = mock((
|
|
91
|
+
const handler = mock((_entry: ErrorLogEntry) => {});
|
|
92
92
|
setErrorHandler(handler);
|
|
93
93
|
|
|
94
94
|
logNetworkError('api.fetch', new Error('test'), { endpoint: '/api/test' });
|
|
95
95
|
|
|
96
|
-
const entry = (handler.mock.calls as [ErrorLogEntry][])[0][0];
|
|
96
|
+
const entry = (handler.mock.calls as [ErrorLogEntry][])[0]![0];
|
|
97
97
|
expect(entry.context).toEqual({ endpoint: '/api/test' });
|
|
98
98
|
});
|
|
99
99
|
});
|
|
@@ -40,11 +40,7 @@ function isDevelopment(): boolean {
|
|
|
40
40
|
* Log runtime error with context
|
|
41
41
|
* Use for graceful degradation scenarios where error is handled but should be visible
|
|
42
42
|
*/
|
|
43
|
-
export function logRuntimeError(
|
|
44
|
-
location: string,
|
|
45
|
-
error: unknown,
|
|
46
|
-
context?: Record<string, unknown>
|
|
47
|
-
): void {
|
|
43
|
+
export function logRuntimeError(location: string, error: unknown, context?: Record<string, unknown>): void {
|
|
48
44
|
const entry: ErrorLogEntry = {
|
|
49
45
|
location,
|
|
50
46
|
category: 'runtime',
|
|
@@ -66,11 +62,7 @@ export function logRuntimeError(
|
|
|
66
62
|
/**
|
|
67
63
|
* Log network/API error
|
|
68
64
|
*/
|
|
69
|
-
export function logNetworkError(
|
|
70
|
-
location: string,
|
|
71
|
-
error: unknown,
|
|
72
|
-
context?: Record<string, unknown>
|
|
73
|
-
): void {
|
|
65
|
+
export function logNetworkError(location: string, error: unknown, context?: Record<string, unknown>): void {
|
|
74
66
|
const entry: ErrorLogEntry = {
|
|
75
67
|
location,
|
|
76
68
|
category: 'network',
|
|
@@ -27,23 +27,12 @@ describe('createError', () => {
|
|
|
27
27
|
|
|
28
28
|
test('creates error with cause', () => {
|
|
29
29
|
const cause = new Error('Original error');
|
|
30
|
-
const error = createError(
|
|
31
|
-
'internal',
|
|
32
|
-
'WRAPPED',
|
|
33
|
-
'Wrapped message',
|
|
34
|
-
undefined,
|
|
35
|
-
cause
|
|
36
|
-
);
|
|
30
|
+
const error = createError('internal', 'WRAPPED', 'Wrapped message', undefined, cause);
|
|
37
31
|
expect(error.cause).toBe(cause);
|
|
38
32
|
});
|
|
39
33
|
|
|
40
34
|
test('creates error for each category', () => {
|
|
41
|
-
const categories = [
|
|
42
|
-
'validation',
|
|
43
|
-
'runtime',
|
|
44
|
-
'network',
|
|
45
|
-
'internal',
|
|
46
|
-
] as const;
|
|
35
|
+
const categories = ['validation', 'runtime', 'network', 'internal'] as const;
|
|
47
36
|
for (const category of categories) {
|
|
48
37
|
const error = createError(category, 'CODE', 'message');
|
|
49
38
|
expect(error.category).toBe(category);
|