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
|
@@ -10,11 +10,10 @@ import type {
|
|
|
10
10
|
CMSItemVersions,
|
|
11
11
|
CMSRouteMatch,
|
|
12
12
|
CMSListQuery,
|
|
13
|
-
CMSFilterCondition,
|
|
14
|
-
CMSSortConfig,
|
|
15
13
|
ReferenceLocation,
|
|
16
14
|
} from '../../shared/types';
|
|
17
15
|
import { isItemDraftForLocale } from '../../shared/types';
|
|
16
|
+
import { applyCmsFilters, applyCmsSorting } from '../../shared/cmsQuery';
|
|
18
17
|
import { isI18nValue } from '../../shared/i18n';
|
|
19
18
|
import { tiptapToHtml } from '../../shared/richtext/tiptapToHtml';
|
|
20
19
|
import { isTiptapDocument } from '../../shared/richtext/types';
|
|
@@ -144,7 +143,7 @@ export class CMSService {
|
|
|
144
143
|
if (richTextFields.length === 0) return items;
|
|
145
144
|
|
|
146
145
|
// Process each item
|
|
147
|
-
return items.map(item => {
|
|
146
|
+
return items.map((item) => {
|
|
148
147
|
const processed = { ...item };
|
|
149
148
|
|
|
150
149
|
for (const fieldName of richTextFields) {
|
|
@@ -199,6 +198,9 @@ export class CMSService {
|
|
|
199
198
|
|
|
200
199
|
for (const [id, schemaInfo] of schemas) {
|
|
201
200
|
newSchemaCache.set(id, schemaInfo);
|
|
201
|
+
// A data-only collection (no urlPattern) has no per-item route, so it contributes
|
|
202
|
+
// no route pattern — matchRoute never resolves it, which is correct (it's list-only).
|
|
203
|
+
if (!schemaInfo.schema.urlPattern) continue;
|
|
202
204
|
newRoutePatterns.push({
|
|
203
205
|
regex: this.patternToRegex(schemaInfo.schema.urlPattern),
|
|
204
206
|
collection: id,
|
|
@@ -240,6 +242,7 @@ export class CMSService {
|
|
|
240
242
|
const match = path.match(route.regex);
|
|
241
243
|
if (match) {
|
|
242
244
|
const urlSlug = match[route.slugGroup];
|
|
245
|
+
if (urlSlug === undefined) continue;
|
|
243
246
|
|
|
244
247
|
// Try to find item by matching its slug field value
|
|
245
248
|
const item = await this.findItemBySlug(route.collection, urlSlug, locale);
|
|
@@ -264,11 +267,7 @@ export class CMSService {
|
|
|
264
267
|
* @param slugField - Field name containing the slug
|
|
265
268
|
* @returns CMSItem if found, null otherwise
|
|
266
269
|
*/
|
|
267
|
-
private findBySimpleSlug(
|
|
268
|
-
items: CMSItem[],
|
|
269
|
-
urlSlug: string,
|
|
270
|
-
slugField: string
|
|
271
|
-
): CMSItem | null {
|
|
270
|
+
private findBySimpleSlug(items: CMSItem[], urlSlug: string, slugField: string): CMSItem | null {
|
|
272
271
|
for (const item of items) {
|
|
273
272
|
const slugValue = item[slugField];
|
|
274
273
|
|
|
@@ -291,12 +290,7 @@ export class CMSService {
|
|
|
291
290
|
* @param locale - Optional locale for preferential matching
|
|
292
291
|
* @returns CMSItem if found, null otherwise
|
|
293
292
|
*/
|
|
294
|
-
private findByI18nSlug(
|
|
295
|
-
items: CMSItem[],
|
|
296
|
-
urlSlug: string,
|
|
297
|
-
slugField: string,
|
|
298
|
-
locale?: string
|
|
299
|
-
): CMSItem | null {
|
|
293
|
+
private findByI18nSlug(items: CMSItem[], urlSlug: string, slugField: string, locale?: string): CMSItem | null {
|
|
300
294
|
for (const item of items) {
|
|
301
295
|
const slugValue = item[slugField];
|
|
302
296
|
|
|
@@ -324,11 +318,7 @@ export class CMSService {
|
|
|
324
318
|
* @param locale - Optional locale for i18n slug matching
|
|
325
319
|
* @returns CMSItem if found, null otherwise
|
|
326
320
|
*/
|
|
327
|
-
private async findItemBySlug(
|
|
328
|
-
collection: string,
|
|
329
|
-
urlSlug: string,
|
|
330
|
-
locale?: string
|
|
331
|
-
): Promise<CMSItem | null> {
|
|
321
|
+
private async findItemBySlug(collection: string, urlSlug: string, locale?: string): Promise<CMSItem | null> {
|
|
332
322
|
if (!this.provider) {
|
|
333
323
|
return null;
|
|
334
324
|
}
|
|
@@ -339,6 +329,9 @@ export class CMSService {
|
|
|
339
329
|
const slugField = schemaInfo.schema.slugField;
|
|
340
330
|
const items = await this.getCachedItems(collection);
|
|
341
331
|
|
|
332
|
+
// A data-only collection has no slug field — only the filename fallback can match.
|
|
333
|
+
if (!slugField) return await this.provider.getItemByFilename(collection, urlSlug);
|
|
334
|
+
|
|
342
335
|
// Try simple string slug match first
|
|
343
336
|
const simpleMatch = this.findBySimpleSlug(items, urlSlug, slugField);
|
|
344
337
|
if (simpleMatch) return simpleMatch;
|
|
@@ -363,7 +356,7 @@ export class CMSService {
|
|
|
363
356
|
collection: string,
|
|
364
357
|
locales?: string[],
|
|
365
358
|
defaultLocale?: string,
|
|
366
|
-
options?: { excludeDrafts?: boolean }
|
|
359
|
+
options?: { excludeDrafts?: boolean },
|
|
367
360
|
): Promise<string[]> {
|
|
368
361
|
if (!this.provider) {
|
|
369
362
|
return [];
|
|
@@ -371,20 +364,21 @@ export class CMSService {
|
|
|
371
364
|
|
|
372
365
|
const schemaInfo = this.schemaCache.get(collection);
|
|
373
366
|
if (!schemaInfo) return [];
|
|
367
|
+
// A data-only collection (no urlPattern/slugField) contributes no sitemap URLs.
|
|
368
|
+
const { urlPattern, slugField } = schemaInfo.schema;
|
|
369
|
+
if (!urlPattern || !slugField) return [];
|
|
374
370
|
|
|
375
371
|
const items = await this.getCachedItems(collection);
|
|
376
372
|
const urls: string[] = [];
|
|
377
373
|
|
|
378
374
|
for (const item of items) {
|
|
379
|
-
const slugValue = item[
|
|
375
|
+
const slugValue = item[slugField];
|
|
380
376
|
|
|
381
377
|
// Case 1: Simple string slug - one URL
|
|
382
378
|
if (typeof slugValue === 'string') {
|
|
383
379
|
// Skip if item is draft for the default locale (non-i18n case)
|
|
384
380
|
if (options?.excludeDrafts && defaultLocale && isItemDraftForLocale(item, defaultLocale)) continue;
|
|
385
|
-
urls.push(
|
|
386
|
-
schemaInfo.schema.urlPattern.replace('{{slug}}', slugValue)
|
|
387
|
-
);
|
|
381
|
+
urls.push(urlPattern.replace('{{slug}}', slugValue));
|
|
388
382
|
}
|
|
389
383
|
// Case 2: i18n slug - one URL per locale
|
|
390
384
|
else if (isI18nValue(slugValue) && locales) {
|
|
@@ -392,7 +386,7 @@ export class CMSService {
|
|
|
392
386
|
if (options?.excludeDrafts && isItemDraftForLocale(item, locale)) continue;
|
|
393
387
|
const localizedSlug = slugValue[locale] as string;
|
|
394
388
|
if (localizedSlug) {
|
|
395
|
-
const path =
|
|
389
|
+
const path = urlPattern.replace('{{slug}}', localizedSlug);
|
|
396
390
|
// For default locale, no prefix; for others, add locale prefix
|
|
397
391
|
if (locale === defaultLocale) {
|
|
398
392
|
urls.push(path);
|
|
@@ -406,9 +400,7 @@ export class CMSService {
|
|
|
406
400
|
else if (isI18nValue(slugValue)) {
|
|
407
401
|
for (const key of Object.keys(slugValue)) {
|
|
408
402
|
if (key !== '_i18n' && typeof slugValue[key] === 'string') {
|
|
409
|
-
urls.push(
|
|
410
|
-
schemaInfo.schema.urlPattern.replace('{{slug}}', slugValue[key] as string)
|
|
411
|
-
);
|
|
403
|
+
urls.push(urlPattern.replace('{{slug}}', slugValue[key] as string));
|
|
412
404
|
break; // Only use first available
|
|
413
405
|
}
|
|
414
406
|
}
|
|
@@ -474,17 +466,17 @@ export class CMSService {
|
|
|
474
466
|
this.provider.getAllDrafts(collection),
|
|
475
467
|
]);
|
|
476
468
|
|
|
477
|
-
const draftFilenames = new Set(drafts.map(d => d._filename).filter(Boolean) as string[]);
|
|
469
|
+
const draftFilenames = new Set(drafts.map((d) => d._filename).filter(Boolean) as string[]);
|
|
478
470
|
|
|
479
|
-
const annotatedPublished: CMSItem[] = published.map(item => {
|
|
471
|
+
const annotatedPublished: CMSItem[] = published.map((item) => {
|
|
480
472
|
if (item._filename && draftFilenames.has(item._filename)) {
|
|
481
473
|
return { ...item, _hasDraft: true };
|
|
482
474
|
}
|
|
483
475
|
return item;
|
|
484
476
|
});
|
|
485
477
|
|
|
486
|
-
const publishedFilenames = new Set(published.map(i => i._filename).filter(Boolean) as string[]);
|
|
487
|
-
const draftOnly = drafts.filter(d => d._filename && !publishedFilenames.has(d._filename));
|
|
478
|
+
const publishedFilenames = new Set(published.map((i) => i._filename).filter(Boolean) as string[]);
|
|
479
|
+
const draftOnly = drafts.filter((d) => d._filename && !publishedFilenames.has(d._filename));
|
|
488
480
|
|
|
489
481
|
return [...annotatedPublished, ...draftOnly];
|
|
490
482
|
}
|
|
@@ -574,17 +566,17 @@ export class CMSService {
|
|
|
574
566
|
|
|
575
567
|
// Exclude draft items for the specified locale
|
|
576
568
|
if (query.excludeDraftLocale) {
|
|
577
|
-
items = items.filter(item => !isItemDraftForLocale(item, query.excludeDraftLocale!));
|
|
569
|
+
items = items.filter((item) => !isItemDraftForLocale(item, query.excludeDraftLocale!));
|
|
578
570
|
}
|
|
579
571
|
|
|
580
572
|
// Apply filters
|
|
581
573
|
if (query.filter) {
|
|
582
|
-
items =
|
|
574
|
+
items = applyCmsFilters(items, query.filter);
|
|
583
575
|
}
|
|
584
576
|
|
|
585
577
|
// Apply sorting
|
|
586
578
|
if (query.sort) {
|
|
587
|
-
items =
|
|
579
|
+
items = applyCmsSorting(items, query.sort);
|
|
588
580
|
}
|
|
589
581
|
|
|
590
582
|
// Apply offset
|
|
@@ -600,63 +592,6 @@ export class CMSService {
|
|
|
600
592
|
return items;
|
|
601
593
|
}
|
|
602
594
|
|
|
603
|
-
/**
|
|
604
|
-
* Apply filters to items
|
|
605
|
-
*/
|
|
606
|
-
private applyFilters(
|
|
607
|
-
items: CMSItem[],
|
|
608
|
-
filter: CMSFilterCondition | CMSFilterCondition[] | Record<string, unknown>
|
|
609
|
-
): CMSItem[] {
|
|
610
|
-
// Handle simple object filter: { featured: true }
|
|
611
|
-
if (!Array.isArray(filter) && !this.isFilterCondition(filter)) {
|
|
612
|
-
return items.filter(item =>
|
|
613
|
-
Object.entries(filter).every(([key, value]) => item[key] === value)
|
|
614
|
-
);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Handle array of conditions or single condition
|
|
618
|
-
const conditions = Array.isArray(filter) ? filter : [filter as CMSFilterCondition];
|
|
619
|
-
return items.filter(item =>
|
|
620
|
-
conditions.every(cond => this.matchCondition(item, cond))
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* Check if object is a CMSFilterCondition
|
|
626
|
-
*/
|
|
627
|
-
private isFilterCondition(obj: unknown): obj is CMSFilterCondition {
|
|
628
|
-
return typeof obj === 'object' && obj !== null && 'field' in obj;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
/**
|
|
632
|
-
* Match a single filter condition against an item
|
|
633
|
-
*/
|
|
634
|
-
private matchCondition(item: CMSItem, condition: CMSFilterCondition): boolean {
|
|
635
|
-
const value = item[condition.field];
|
|
636
|
-
const op = condition.operator || 'eq';
|
|
637
|
-
|
|
638
|
-
switch (op) {
|
|
639
|
-
case 'eq':
|
|
640
|
-
return value === condition.value;
|
|
641
|
-
case 'neq':
|
|
642
|
-
return value !== condition.value;
|
|
643
|
-
case 'gt':
|
|
644
|
-
return (value as number) > (condition.value as number);
|
|
645
|
-
case 'gte':
|
|
646
|
-
return (value as number) >= (condition.value as number);
|
|
647
|
-
case 'lt':
|
|
648
|
-
return (value as number) < (condition.value as number);
|
|
649
|
-
case 'lte':
|
|
650
|
-
return (value as number) <= (condition.value as number);
|
|
651
|
-
case 'contains':
|
|
652
|
-
return String(value).includes(String(condition.value));
|
|
653
|
-
case 'in':
|
|
654
|
-
return Array.isArray(condition.value) && condition.value.includes(value);
|
|
655
|
-
default:
|
|
656
|
-
return false;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
595
|
/**
|
|
661
596
|
* Get items by their IDs from a collection.
|
|
662
597
|
* Used for resolving reference fields in CMS List templates.
|
|
@@ -674,56 +609,16 @@ export class CMSService {
|
|
|
674
609
|
const allItems = await this.getCachedItems(collection);
|
|
675
610
|
|
|
676
611
|
// Build lookup maps for both _id and _filename
|
|
677
|
-
const itemMap = new Map(allItems.map(item => [item._id, item]));
|
|
678
|
-
const filenameMap = new Map(
|
|
679
|
-
allItems
|
|
680
|
-
.filter(item => item._filename)
|
|
681
|
-
.map(item => [item._filename!, item])
|
|
682
|
-
);
|
|
612
|
+
const itemMap = new Map(allItems.map((item) => [item._id, item]));
|
|
613
|
+
const filenameMap = new Map(allItems.filter((item) => item._filename).map((item) => [item._filename!, item]));
|
|
683
614
|
|
|
684
615
|
// Filter to matching items, preserving input order
|
|
685
616
|
return ids
|
|
686
617
|
.filter(Boolean)
|
|
687
|
-
.map(id => itemMap.get(id) || filenameMap.get(id))
|
|
618
|
+
.map((id) => itemMap.get(id) || filenameMap.get(id))
|
|
688
619
|
.filter((item): item is CMSItem => item !== undefined);
|
|
689
620
|
}
|
|
690
621
|
|
|
691
|
-
/**
|
|
692
|
-
* Apply sorting to items
|
|
693
|
-
*/
|
|
694
|
-
private applySorting(items: CMSItem[], sort: CMSSortConfig | CMSSortConfig[]): CMSItem[] {
|
|
695
|
-
const sorts = Array.isArray(sort) ? sort : [sort];
|
|
696
|
-
|
|
697
|
-
return [...items].sort((a, b) => {
|
|
698
|
-
for (const s of sorts) {
|
|
699
|
-
const aVal = a[s.field];
|
|
700
|
-
const bVal = b[s.field];
|
|
701
|
-
const isDesc = s.order === 'desc';
|
|
702
|
-
|
|
703
|
-
// Handle boolean comparison
|
|
704
|
-
if (typeof aVal === 'boolean' && typeof bVal === 'boolean') {
|
|
705
|
-
if (aVal === bVal) continue;
|
|
706
|
-
// For desc: true first (true > false), for asc: false first
|
|
707
|
-
if (isDesc) {
|
|
708
|
-
return aVal ? -1 : 1;
|
|
709
|
-
} else {
|
|
710
|
-
return aVal ? 1 : -1;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// Standard comparison (compare as primitives)
|
|
715
|
-
let result = 0;
|
|
716
|
-
if ((aVal as string | number) < (bVal as string | number)) result = -1;
|
|
717
|
-
else if ((aVal as string | number) > (bVal as string | number)) result = 1;
|
|
718
|
-
|
|
719
|
-
if (result !== 0) {
|
|
720
|
-
return isDesc ? -result : result;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
return 0;
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
|
|
727
622
|
/**
|
|
728
623
|
* Find all references to a specific item across all collections.
|
|
729
624
|
* Used to warn users before deleting an item that is referenced elsewhere.
|
|
@@ -732,10 +627,7 @@ export class CMSService {
|
|
|
732
627
|
* @param targetId - ID or filename of the target item
|
|
733
628
|
* @returns Array of ReferenceLocation objects describing where the item is referenced
|
|
734
629
|
*/
|
|
735
|
-
async findReferencesTo(
|
|
736
|
-
targetCollection: string,
|
|
737
|
-
targetId: string
|
|
738
|
-
): Promise<ReferenceLocation[]> {
|
|
630
|
+
async findReferencesTo(targetCollection: string, targetId: string): Promise<ReferenceLocation[]> {
|
|
739
631
|
if (!this.provider) {
|
|
740
632
|
return [];
|
|
741
633
|
}
|
|
@@ -747,8 +639,9 @@ export class CMSService {
|
|
|
747
639
|
const { schema } = schemaInfo;
|
|
748
640
|
|
|
749
641
|
// Find reference fields pointing to targetCollection
|
|
750
|
-
const refFields = Object.entries(schema.fields)
|
|
751
|
-
|
|
642
|
+
const refFields = Object.entries(schema.fields).filter(
|
|
643
|
+
([_, def]) => def.type === 'reference' && def.collection === targetCollection,
|
|
644
|
+
);
|
|
752
645
|
|
|
753
646
|
if (refFields.length === 0) continue;
|
|
754
647
|
|
|
@@ -782,10 +675,7 @@ export class CMSService {
|
|
|
782
675
|
* For multi-reference fields: filters out the target ID
|
|
783
676
|
* @returns Number of items updated
|
|
784
677
|
*/
|
|
785
|
-
async removeReferencesTo(
|
|
786
|
-
targetCollection: string,
|
|
787
|
-
targetId: string
|
|
788
|
-
): Promise<number> {
|
|
678
|
+
async removeReferencesTo(targetCollection: string, targetId: string): Promise<number> {
|
|
789
679
|
if (!this.provider) {
|
|
790
680
|
return 0;
|
|
791
681
|
}
|
|
@@ -806,7 +696,7 @@ export class CMSService {
|
|
|
806
696
|
let newValue: string | string[] | null;
|
|
807
697
|
if (fieldDef?.multiple && Array.isArray(currentValue)) {
|
|
808
698
|
// Multi-reference: filter out target
|
|
809
|
-
newValue = currentValue.filter(id => id !== targetId);
|
|
699
|
+
newValue = currentValue.filter((id) => id !== targetId);
|
|
810
700
|
if (newValue.length === 0) newValue = null;
|
|
811
701
|
} else {
|
|
812
702
|
// Single reference: clear it
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { test, expect, describe, beforeEach, afterAll
|
|
2
|
-
import { mkdtempSync, rmSync, existsSync, readFileSync, mkdirSync } from 'fs';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import { ComponentService, rewriteComponentRefs, type
|
|
1
|
+
import { test, expect, describe, beforeEach, afterAll } from 'bun:test';
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync, readFileSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { ComponentService, rewriteComponentRefs, type ComponentWriter } from './componentService';
|
|
6
6
|
import { setProjectRoot, getProjectRoot, projectPaths } from '../projectContext';
|
|
7
7
|
import { createMockComponentDefinition } from '../../test-utils';
|
|
8
8
|
import {
|
|
@@ -108,8 +108,8 @@ describe('ComponentService', () => {
|
|
|
108
108
|
const allComponents = componentService.getAllComponents();
|
|
109
109
|
|
|
110
110
|
expect(allComponents).toBeDefined();
|
|
111
|
-
expect(allComponents
|
|
112
|
-
expect(allComponents
|
|
111
|
+
expect(allComponents.TestComponent).toBeDefined();
|
|
112
|
+
expect(allComponents.Button).toBeDefined();
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
test('should return empty object when no components loaded', () => {
|
|
@@ -135,33 +135,41 @@ describe('ComponentService', () => {
|
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
test('should return false for missing structure', () => {
|
|
138
|
-
expect(
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
expect(
|
|
139
|
+
componentService.validateComponentStructure({
|
|
140
|
+
component: {},
|
|
141
|
+
} as any),
|
|
142
|
+
).toBe(false);
|
|
141
143
|
});
|
|
142
144
|
|
|
143
145
|
test('should return false for invalid structure type', () => {
|
|
144
|
-
expect(
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
expect(
|
|
147
|
+
componentService.validateComponentStructure({
|
|
148
|
+
component: { structure: 'invalid' },
|
|
149
|
+
} as any),
|
|
150
|
+
).toBe(false);
|
|
147
151
|
});
|
|
148
152
|
|
|
149
153
|
test('should return false for structure without type', () => {
|
|
150
|
-
expect(
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
expect(
|
|
155
|
+
componentService.validateComponentStructure({
|
|
156
|
+
component: { structure: { tag: 'div' } },
|
|
157
|
+
} as any),
|
|
158
|
+
).toBe(false);
|
|
153
159
|
});
|
|
154
160
|
|
|
155
161
|
test('should return true for structure with valid type', () => {
|
|
156
|
-
expect(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
expect(
|
|
163
|
+
componentService.validateComponentStructure({
|
|
164
|
+
component: {
|
|
165
|
+
structure: {
|
|
166
|
+
type: NODE_TYPE.NODE,
|
|
167
|
+
tag: 'div',
|
|
168
|
+
children: [],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
} as any),
|
|
172
|
+
).toBe(true);
|
|
165
173
|
});
|
|
166
174
|
});
|
|
167
175
|
|
|
@@ -209,6 +217,67 @@ describe('ComponentService', () => {
|
|
|
209
217
|
|
|
210
218
|
expect(filePath).toContain('Button.json');
|
|
211
219
|
});
|
|
220
|
+
|
|
221
|
+
test('keeps javascript in the in-memory cache (JSON payload stays js-less)', async () => {
|
|
222
|
+
// The `.json` file must not carry javascript (the sibling `.js` owns it), but the
|
|
223
|
+
// LIVE cache must — otherwise the SSR preview renders the component without its
|
|
224
|
+
// script between this save and the next file-watcher reload.
|
|
225
|
+
const componentData = createMockComponentDefinition('TestComponent');
|
|
226
|
+
if (componentData.component) {
|
|
227
|
+
componentData.component.javascript = 'console.log("kept");';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
await componentService.saveComponent('TestComponent', componentData);
|
|
231
|
+
|
|
232
|
+
const savedData = JSON.parse((mockFs.writeFile as any).mock.calls[0][1]);
|
|
233
|
+
expect(savedData.component.javascript).toBeUndefined();
|
|
234
|
+
expect(componentService.getComponent('TestComponent')?.component?.javascript).toBe('console.log("kept");');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test('a js-less save preserves the previously cached javascript', async () => {
|
|
238
|
+
// A props/structure-only save (the common PropsPanel edit) must not erase the
|
|
239
|
+
// component's script from the cache.
|
|
240
|
+
const withJs = createMockComponentDefinition('TestComponent');
|
|
241
|
+
if (withJs.component) withJs.component.javascript = 'console.log("orig");';
|
|
242
|
+
await componentService.saveComponent('TestComponent', withJs);
|
|
243
|
+
|
|
244
|
+
const withoutJs = createMockComponentDefinition('TestComponent');
|
|
245
|
+
await componentService.saveComponent('TestComponent', withoutJs);
|
|
246
|
+
|
|
247
|
+
expect(componentService.getComponent('TestComponent')?.component?.javascript).toBe('console.log("orig");');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('saveComponent with a single-file writer (astro format)', () => {
|
|
252
|
+
test('the writer receives the FULL def — javascript preserved, not stripped', async () => {
|
|
253
|
+
// Single-file writers (AstroComponentWriter) re-emit the WHOLE file from the def
|
|
254
|
+
// they're given: a js-less def would silently delete the component's <script>
|
|
255
|
+
// from the source of truth. Regression test for the rename-cascade data loss.
|
|
256
|
+
const written: ComponentDefinition[] = [];
|
|
257
|
+
const writer: ComponentWriter = {
|
|
258
|
+
componentsDir: () => '/tmp/fake-components',
|
|
259
|
+
writeComponent: async (_dir, _name, def) => {
|
|
260
|
+
written.push(def);
|
|
261
|
+
},
|
|
262
|
+
writeJavaScript: async () => {},
|
|
263
|
+
writeCSS: async () => {},
|
|
264
|
+
removeComponent: async () => {},
|
|
265
|
+
componentExists: async () => false,
|
|
266
|
+
moveComponent: async () => {},
|
|
267
|
+
};
|
|
268
|
+
const service = new ComponentService({ loader: mockLoader, writer });
|
|
269
|
+
|
|
270
|
+
const withJs = createMockComponentDefinition('Header');
|
|
271
|
+
if (withJs.component) withJs.component.javascript = 'menuToggle();';
|
|
272
|
+
await service.saveComponent('Header', withJs);
|
|
273
|
+
expect(written[0]?.component?.javascript).toBe('menuToggle();');
|
|
274
|
+
|
|
275
|
+
// A js-less follow-up save (props-only edit, or the href-rename cascade
|
|
276
|
+
// re-saving a cached def) keeps the cached script in the emitted file.
|
|
277
|
+
const withoutJs = createMockComponentDefinition('Header');
|
|
278
|
+
await service.saveComponent('Header', withoutJs);
|
|
279
|
+
expect(written[1]?.component?.javascript).toBe('menuToggle();');
|
|
280
|
+
});
|
|
212
281
|
});
|
|
213
282
|
|
|
214
283
|
describe('saveComponentJavaScript', () => {
|
|
@@ -260,10 +329,14 @@ describe('ComponentService', () => {
|
|
|
260
329
|
tag: 'div',
|
|
261
330
|
children: [
|
|
262
331
|
{ type: 'component', component: 'Old' },
|
|
263
|
-
{
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
332
|
+
{
|
|
333
|
+
type: 'node',
|
|
334
|
+
tag: 'section',
|
|
335
|
+
children: [
|
|
336
|
+
{ type: 'component', component: 'Old', props: { text: 'hi' } },
|
|
337
|
+
{ type: 'component', component: 'Keep' },
|
|
338
|
+
],
|
|
339
|
+
},
|
|
267
340
|
],
|
|
268
341
|
};
|
|
269
342
|
|
|
@@ -271,8 +344,8 @@ describe('ComponentService', () => {
|
|
|
271
344
|
|
|
272
345
|
expect(changed).toBe(true);
|
|
273
346
|
expect((tree.children[0] as any).component).toBe('New');
|
|
274
|
-
expect((
|
|
275
|
-
expect((
|
|
347
|
+
expect((tree.children[1] as any).children[0].component).toBe('New');
|
|
348
|
+
expect((tree.children[1] as any).children[1].component).toBe('Keep');
|
|
276
349
|
});
|
|
277
350
|
|
|
278
351
|
test('returns false when no references match', () => {
|
|
@@ -293,10 +366,7 @@ describe('ComponentService', () => {
|
|
|
293
366
|
type: 'node',
|
|
294
367
|
tag: 'button',
|
|
295
368
|
attributes: { class: 'Button primary' },
|
|
296
|
-
children: [
|
|
297
|
-
{ type: 'embed', html: '<button>Button</button>' },
|
|
298
|
-
'Click the Button below',
|
|
299
|
-
],
|
|
369
|
+
children: [{ type: 'embed', html: '<button>Button</button>' }, 'Click the Button below'],
|
|
300
370
|
};
|
|
301
371
|
|
|
302
372
|
const changed = rewriteComponentRefs(tree, 'Button', 'Cta');
|
|
@@ -395,12 +465,22 @@ describe('ComponentService', () => {
|
|
|
395
465
|
const dir = '/virtual/src/components';
|
|
396
466
|
const writer: ComponentWriter = {
|
|
397
467
|
componentsDir: () => dir,
|
|
398
|
-
writeComponent: async (d, n) => {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
468
|
+
writeComponent: async (d, n) => {
|
|
469
|
+
calls.push({ op: 'writeComponent', dir: d, name: n });
|
|
470
|
+
},
|
|
471
|
+
writeJavaScript: async (d, n, js) => {
|
|
472
|
+
calls.push({ op: 'writeJavaScript', dir: d, name: n, extra: js });
|
|
473
|
+
},
|
|
474
|
+
writeCSS: async (d, n, css) => {
|
|
475
|
+
calls.push({ op: 'writeCSS', dir: d, name: n, extra: css });
|
|
476
|
+
},
|
|
477
|
+
removeComponent: async (d, n) => {
|
|
478
|
+
calls.push({ op: 'removeComponent', dir: d, name: n });
|
|
479
|
+
},
|
|
402
480
|
componentExists: async () => false,
|
|
403
|
-
moveComponent: async (s, t, n, dn) => {
|
|
481
|
+
moveComponent: async (s, t, n, dn) => {
|
|
482
|
+
calls.push({ op: 'moveComponent', dir: `${s}->${t}`, name: n, extra: dn });
|
|
483
|
+
},
|
|
404
484
|
};
|
|
405
485
|
return { writer, calls, dir };
|
|
406
486
|
}
|
|
@@ -410,9 +490,9 @@ describe('ComponentService', () => {
|
|
|
410
490
|
const svc = new ComponentService({ writer });
|
|
411
491
|
await svc.saveComponent('Widget', createMockComponentDefinition('Widget'));
|
|
412
492
|
expect(calls).toHaveLength(1);
|
|
413
|
-
expect(calls[0]
|
|
414
|
-
expect(calls[0]
|
|
415
|
-
expect(calls[0]
|
|
493
|
+
expect(calls[0]!.op).toBe('writeComponent');
|
|
494
|
+
expect(calls[0]!.dir).toBe(dir);
|
|
495
|
+
expect(calls[0]!.name).toBe('Widget');
|
|
416
496
|
expect(svc.hasComponent('Widget')).toBe(true);
|
|
417
497
|
});
|
|
418
498
|
|
|
@@ -422,7 +502,7 @@ describe('ComponentService', () => {
|
|
|
422
502
|
await svc.saveComponent('Widget', createMockComponentDefinition('Widget'));
|
|
423
503
|
await svc.saveComponentCSS('Widget', '.w{}');
|
|
424
504
|
await svc.saveComponentJavaScript('Widget', 'x();');
|
|
425
|
-
const ops = calls.map(c => c.op);
|
|
505
|
+
const ops = calls.map((c) => c.op);
|
|
426
506
|
expect(ops).toEqual(['writeComponent', 'writeCSS', 'writeJavaScript']);
|
|
427
507
|
const cached = svc.getComponent('Widget');
|
|
428
508
|
expect(cached?.component?.css).toBe('.w{}');
|
|
@@ -437,7 +517,7 @@ describe('ComponentService', () => {
|
|
|
437
517
|
});
|
|
438
518
|
await svc.loadAllComponents();
|
|
439
519
|
await svc.renameComponent('Widget', 'Gadget');
|
|
440
|
-
const move = calls.find(c => c.op === 'moveComponent');
|
|
520
|
+
const move = calls.find((c) => c.op === 'moveComponent');
|
|
441
521
|
expect(move).toBeDefined();
|
|
442
522
|
expect(move!.name).toBe('Widget');
|
|
443
523
|
expect(move!.extra).toBe('Gadget'); // dstName
|