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
|
@@ -65,15 +65,65 @@ const mockAuthorItems: CMSItem[] = [
|
|
|
65
65
|
];
|
|
66
66
|
|
|
67
67
|
const mockBlogItems: CMSItem[] = [
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
{
|
|
69
|
+
_id: '1',
|
|
70
|
+
_filename: 'hello-world',
|
|
71
|
+
_slug: 'hello-world',
|
|
72
|
+
slug: 'hello-world',
|
|
73
|
+
title: 'Hello World',
|
|
74
|
+
content: 'First post',
|
|
75
|
+
author: 'john-doe',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
_id: '2',
|
|
79
|
+
_filename: 'getting-started',
|
|
80
|
+
_slug: 'getting-started',
|
|
81
|
+
slug: 'getting-started',
|
|
82
|
+
title: 'Getting Started',
|
|
83
|
+
content: 'Guide',
|
|
84
|
+
author: 'john-doe',
|
|
85
|
+
relatedPosts: ['hello-world'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
_id: '3',
|
|
89
|
+
_filename: 'advanced-tips',
|
|
90
|
+
_slug: 'advanced-tips',
|
|
91
|
+
slug: 'advanced-tips',
|
|
92
|
+
title: 'Advanced Tips',
|
|
93
|
+
content: 'Pro tips',
|
|
94
|
+
author: 'jane-smith',
|
|
95
|
+
relatedPosts: ['hello-world', 'getting-started'],
|
|
96
|
+
},
|
|
71
97
|
];
|
|
72
98
|
|
|
73
99
|
const mockProductItems: CMSItem[] = [
|
|
74
|
-
{
|
|
75
|
-
|
|
76
|
-
|
|
100
|
+
{
|
|
101
|
+
_id: '1',
|
|
102
|
+
_filename: 'laptop',
|
|
103
|
+
slug: 'laptop',
|
|
104
|
+
name: 'Laptop Pro',
|
|
105
|
+
price: 999,
|
|
106
|
+
featured: true,
|
|
107
|
+
category: 'Electronics',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
_id: '2',
|
|
111
|
+
_filename: 'tshirt',
|
|
112
|
+
slug: 'tshirt',
|
|
113
|
+
name: 'Cool T-Shirt',
|
|
114
|
+
price: 29,
|
|
115
|
+
featured: false,
|
|
116
|
+
category: 'Clothing',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
_id: '3',
|
|
120
|
+
_filename: 'headphones',
|
|
121
|
+
slug: 'headphones',
|
|
122
|
+
name: 'Wireless Headphones',
|
|
123
|
+
price: 199,
|
|
124
|
+
featured: true,
|
|
125
|
+
category: 'Electronics',
|
|
126
|
+
},
|
|
77
127
|
];
|
|
78
128
|
|
|
79
129
|
describe('CMSService', () => {
|
|
@@ -82,11 +132,12 @@ describe('CMSService', () => {
|
|
|
82
132
|
|
|
83
133
|
beforeEach(async () => {
|
|
84
134
|
mockProvider = {
|
|
85
|
-
getAllSchemas: async () =>
|
|
86
|
-
[
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
135
|
+
getAllSchemas: async () =>
|
|
136
|
+
new Map([
|
|
137
|
+
['authors', mockAuthorSchemaInfo],
|
|
138
|
+
['blog-posts', mockSchemaInfo],
|
|
139
|
+
['products', mockProductSchemaInfo],
|
|
140
|
+
]),
|
|
90
141
|
getItems: async (collection: string) => {
|
|
91
142
|
if (collection === 'authors') return mockAuthorItems;
|
|
92
143
|
if (collection === 'blog-posts') return mockBlogItems;
|
|
@@ -95,28 +146,28 @@ describe('CMSService', () => {
|
|
|
95
146
|
},
|
|
96
147
|
getItemBySlug: async (collection: string, slug: string) => {
|
|
97
148
|
if (collection === 'blog-posts') {
|
|
98
|
-
return mockBlogItems.find(i => i.slug === slug) || null;
|
|
149
|
+
return mockBlogItems.find((i) => i.slug === slug) || null;
|
|
99
150
|
}
|
|
100
151
|
if (collection === 'products') {
|
|
101
|
-
return mockProductItems.find(i => i.slug === slug) || null;
|
|
152
|
+
return mockProductItems.find((i) => i.slug === slug) || null;
|
|
102
153
|
}
|
|
103
154
|
return null;
|
|
104
155
|
},
|
|
105
156
|
getItemByFilename: async (collection: string, filename: string) => {
|
|
106
157
|
if (collection === 'blog-posts') {
|
|
107
|
-
return mockBlogItems.find(i => i._filename === filename || i.slug === filename) || null;
|
|
158
|
+
return mockBlogItems.find((i) => i._filename === filename || i.slug === filename) || null;
|
|
108
159
|
}
|
|
109
160
|
if (collection === 'products') {
|
|
110
|
-
return mockProductItems.find(i => i._filename === filename || i.slug === filename) || null;
|
|
161
|
+
return mockProductItems.find((i) => i._filename === filename || i.slug === filename) || null;
|
|
111
162
|
}
|
|
112
163
|
return null;
|
|
113
164
|
},
|
|
114
165
|
getItemById: async (collection: string, id: string) => {
|
|
115
166
|
if (collection === 'blog-posts') {
|
|
116
|
-
return mockBlogItems.find(i => i._id === id) || null;
|
|
167
|
+
return mockBlogItems.find((i) => i._id === id) || null;
|
|
117
168
|
}
|
|
118
169
|
if (collection === 'products') {
|
|
119
|
-
return mockProductItems.find(i => i._id === id) || null;
|
|
170
|
+
return mockProductItems.find((i) => i._id === id) || null;
|
|
120
171
|
}
|
|
121
172
|
return null;
|
|
122
173
|
},
|
|
@@ -128,7 +179,9 @@ describe('CMSService', () => {
|
|
|
128
179
|
hasDraft: async () => false,
|
|
129
180
|
saveDraft: async () => {},
|
|
130
181
|
discardDraft: async () => {},
|
|
131
|
-
publishDraft: async () => {
|
|
182
|
+
publishDraft: async () => {
|
|
183
|
+
throw new Error('publishDraft not implemented in default mock');
|
|
184
|
+
},
|
|
132
185
|
};
|
|
133
186
|
service = new CMSService(mockProvider);
|
|
134
187
|
await service.initialize();
|
|
@@ -175,7 +228,7 @@ describe('CMSService', () => {
|
|
|
175
228
|
expect(match).toEqual({
|
|
176
229
|
collection: 'blog-posts',
|
|
177
230
|
slug: 'hello-world',
|
|
178
|
-
item: mockBlogItems[0]
|
|
231
|
+
item: mockBlogItems[0]!,
|
|
179
232
|
pagePath: '/templates/blog-post.json',
|
|
180
233
|
});
|
|
181
234
|
});
|
|
@@ -185,7 +238,7 @@ describe('CMSService', () => {
|
|
|
185
238
|
expect(match).toEqual({
|
|
186
239
|
collection: 'products',
|
|
187
240
|
slug: 'laptop',
|
|
188
|
-
item: mockProductItems[0]
|
|
241
|
+
item: mockProductItems[0]!,
|
|
189
242
|
pagePath: '/templates/product.json',
|
|
190
243
|
});
|
|
191
244
|
});
|
|
@@ -214,20 +267,12 @@ describe('CMSService', () => {
|
|
|
214
267
|
describe('getCollectionURLs', () => {
|
|
215
268
|
it('should return all URLs for blog-posts collection', async () => {
|
|
216
269
|
const urls = await service.getCollectionURLs('blog-posts');
|
|
217
|
-
expect(urls).toEqual([
|
|
218
|
-
'/blog/hello-world',
|
|
219
|
-
'/blog/getting-started',
|
|
220
|
-
'/blog/advanced-tips',
|
|
221
|
-
]);
|
|
270
|
+
expect(urls).toEqual(['/blog/hello-world', '/blog/getting-started', '/blog/advanced-tips']);
|
|
222
271
|
});
|
|
223
272
|
|
|
224
273
|
it('should return all URLs for products collection', async () => {
|
|
225
274
|
const urls = await service.getCollectionURLs('products');
|
|
226
|
-
expect(urls).toEqual([
|
|
227
|
-
'/shop/laptop',
|
|
228
|
-
'/shop/tshirt',
|
|
229
|
-
'/shop/headphones',
|
|
230
|
-
]);
|
|
275
|
+
expect(urls).toEqual(['/shop/laptop', '/shop/tshirt', '/shop/headphones']);
|
|
231
276
|
});
|
|
232
277
|
|
|
233
278
|
it('should return empty array for unknown collection', async () => {
|
|
@@ -262,7 +307,7 @@ describe('CMSService', () => {
|
|
|
262
307
|
filter: { featured: true },
|
|
263
308
|
});
|
|
264
309
|
expect(items).toHaveLength(2);
|
|
265
|
-
expect(items.every(i => i.featured === true)).toBe(true);
|
|
310
|
+
expect(items.every((i) => i.featured === true)).toBe(true);
|
|
266
311
|
});
|
|
267
312
|
|
|
268
313
|
it('should apply filter with eq operator', async () => {
|
|
@@ -271,7 +316,7 @@ describe('CMSService', () => {
|
|
|
271
316
|
filter: { field: 'category', operator: 'eq', value: 'Electronics' },
|
|
272
317
|
});
|
|
273
318
|
expect(items).toHaveLength(2);
|
|
274
|
-
expect(items.every(i => i.category === 'Electronics')).toBe(true);
|
|
319
|
+
expect(items.every((i) => i.category === 'Electronics')).toBe(true);
|
|
275
320
|
});
|
|
276
321
|
|
|
277
322
|
it('should apply filter with neq operator', async () => {
|
|
@@ -280,7 +325,7 @@ describe('CMSService', () => {
|
|
|
280
325
|
filter: { field: 'category', operator: 'neq', value: 'Electronics' },
|
|
281
326
|
});
|
|
282
327
|
expect(items).toHaveLength(1);
|
|
283
|
-
expect(items[0]
|
|
328
|
+
expect(items[0]!.category).toBe('Clothing');
|
|
284
329
|
});
|
|
285
330
|
|
|
286
331
|
it('should apply filter with gt operator', async () => {
|
|
@@ -289,7 +334,7 @@ describe('CMSService', () => {
|
|
|
289
334
|
filter: { field: 'price', operator: 'gt', value: 100 },
|
|
290
335
|
});
|
|
291
336
|
expect(items).toHaveLength(2);
|
|
292
|
-
expect(items.every(i => (i.price as number) > 100)).toBe(true);
|
|
337
|
+
expect(items.every((i) => (i.price as number) > 100)).toBe(true);
|
|
293
338
|
});
|
|
294
339
|
|
|
295
340
|
it('should apply filter with gte operator', async () => {
|
|
@@ -306,7 +351,7 @@ describe('CMSService', () => {
|
|
|
306
351
|
filter: { field: 'price', operator: 'lt', value: 100 },
|
|
307
352
|
});
|
|
308
353
|
expect(items).toHaveLength(1);
|
|
309
|
-
expect(items[0]
|
|
354
|
+
expect(items[0]!.name).toBe('Cool T-Shirt');
|
|
310
355
|
});
|
|
311
356
|
|
|
312
357
|
it('should apply filter with lte operator', async () => {
|
|
@@ -323,7 +368,7 @@ describe('CMSService', () => {
|
|
|
323
368
|
filter: { field: 'name', operator: 'contains', value: 'Wireless' },
|
|
324
369
|
});
|
|
325
370
|
expect(items).toHaveLength(1);
|
|
326
|
-
expect(items[0]
|
|
371
|
+
expect(items[0]!.slug).toBe('headphones');
|
|
327
372
|
});
|
|
328
373
|
|
|
329
374
|
it('should apply filter with in operator', async () => {
|
|
@@ -350,9 +395,9 @@ describe('CMSService', () => {
|
|
|
350
395
|
collection: 'products',
|
|
351
396
|
sort: { field: 'price', order: 'asc' },
|
|
352
397
|
});
|
|
353
|
-
expect(items[0]
|
|
354
|
-
expect(items[1]
|
|
355
|
-
expect(items[2]
|
|
398
|
+
expect(items[0]!.price).toBe(29);
|
|
399
|
+
expect(items[1]!.price).toBe(199);
|
|
400
|
+
expect(items[2]!.price).toBe(999);
|
|
356
401
|
});
|
|
357
402
|
|
|
358
403
|
it('should apply descending sort', async () => {
|
|
@@ -360,9 +405,9 @@ describe('CMSService', () => {
|
|
|
360
405
|
collection: 'products',
|
|
361
406
|
sort: { field: 'price', order: 'desc' },
|
|
362
407
|
});
|
|
363
|
-
expect(items[0]
|
|
364
|
-
expect(items[1]
|
|
365
|
-
expect(items[2]
|
|
408
|
+
expect(items[0]!.price).toBe(999);
|
|
409
|
+
expect(items[1]!.price).toBe(199);
|
|
410
|
+
expect(items[2]!.price).toBe(29);
|
|
366
411
|
});
|
|
367
412
|
|
|
368
413
|
it('should apply multi-field sort', async () => {
|
|
@@ -374,9 +419,9 @@ describe('CMSService', () => {
|
|
|
374
419
|
],
|
|
375
420
|
});
|
|
376
421
|
// Featured items first (true > false), then by price ascending
|
|
377
|
-
expect(items[0]
|
|
378
|
-
expect(items[1]
|
|
379
|
-
expect(items[2]
|
|
422
|
+
expect(items[0]!.slug).toBe('headphones'); // featured=true, price=199
|
|
423
|
+
expect(items[1]!.slug).toBe('laptop'); // featured=true, price=999
|
|
424
|
+
expect(items[2]!.slug).toBe('tshirt'); // featured=false, price=29
|
|
380
425
|
});
|
|
381
426
|
|
|
382
427
|
it('should apply limit', async () => {
|
|
@@ -393,7 +438,7 @@ describe('CMSService', () => {
|
|
|
393
438
|
offset: 1,
|
|
394
439
|
});
|
|
395
440
|
expect(items).toHaveLength(2);
|
|
396
|
-
expect(items[0]
|
|
441
|
+
expect(items[0]!.slug).toBe('tshirt');
|
|
397
442
|
});
|
|
398
443
|
|
|
399
444
|
it('should apply limit and offset together', async () => {
|
|
@@ -404,7 +449,7 @@ describe('CMSService', () => {
|
|
|
404
449
|
limit: 1,
|
|
405
450
|
});
|
|
406
451
|
expect(items).toHaveLength(1);
|
|
407
|
-
expect(items[0]
|
|
452
|
+
expect(items[0]!.price).toBe(199);
|
|
408
453
|
});
|
|
409
454
|
|
|
410
455
|
it('should return empty array for empty collection', async () => {
|
|
@@ -432,23 +477,23 @@ describe('CMSService', () => {
|
|
|
432
477
|
it('should return items matching IDs in order', async () => {
|
|
433
478
|
const items = await service.getItemsByIds('blog-posts', ['2', '1', '3']);
|
|
434
479
|
expect(items).toHaveLength(3);
|
|
435
|
-
expect(items[0]
|
|
436
|
-
expect(items[1]
|
|
437
|
-
expect(items[2]
|
|
480
|
+
expect(items[0]!._id).toBe('2');
|
|
481
|
+
expect(items[1]!._id).toBe('1');
|
|
482
|
+
expect(items[2]!._id).toBe('3');
|
|
438
483
|
});
|
|
439
484
|
|
|
440
485
|
it('should support _filename lookup', async () => {
|
|
441
486
|
const items = await service.getItemsByIds('blog-posts', ['hello-world', 'advanced-tips']);
|
|
442
487
|
expect(items).toHaveLength(2);
|
|
443
|
-
expect(items[0]
|
|
444
|
-
expect(items[1]
|
|
488
|
+
expect(items[0]!._filename).toBe('hello-world');
|
|
489
|
+
expect(items[1]!._filename).toBe('advanced-tips');
|
|
445
490
|
});
|
|
446
491
|
|
|
447
492
|
it('should filter out non-existent IDs', async () => {
|
|
448
493
|
const items = await service.getItemsByIds('blog-posts', ['1', 'non-existent', '2']);
|
|
449
494
|
expect(items).toHaveLength(2);
|
|
450
|
-
expect(items[0]
|
|
451
|
-
expect(items[1]
|
|
495
|
+
expect(items[0]!._id).toBe('1');
|
|
496
|
+
expect(items[1]!._id).toBe('2');
|
|
452
497
|
});
|
|
453
498
|
|
|
454
499
|
it('should return empty array for empty input', async () => {
|
|
@@ -459,9 +504,9 @@ describe('CMSService', () => {
|
|
|
459
504
|
it('should handle mixed _id and _filename lookups', async () => {
|
|
460
505
|
const items = await service.getItemsByIds('blog-posts', ['1', 'getting-started', '3']);
|
|
461
506
|
expect(items).toHaveLength(3);
|
|
462
|
-
expect(items[0]
|
|
463
|
-
expect(items[1]
|
|
464
|
-
expect(items[2]
|
|
507
|
+
expect(items[0]!._id).toBe('1');
|
|
508
|
+
expect(items[1]!._filename).toBe('getting-started');
|
|
509
|
+
expect(items[2]!._id).toBe('3');
|
|
465
510
|
});
|
|
466
511
|
|
|
467
512
|
it('should return empty array for unknown collection', async () => {
|
|
@@ -480,24 +525,24 @@ describe('CMSService', () => {
|
|
|
480
525
|
// john-doe is referenced by 2 blog posts via 'author' field
|
|
481
526
|
const refs = await service.findReferencesTo('authors', 'john-doe');
|
|
482
527
|
expect(refs).toHaveLength(2);
|
|
483
|
-
expect(refs[0]
|
|
484
|
-
expect(refs[0]
|
|
485
|
-
expect(refs[0]
|
|
486
|
-
expect(refs[1]
|
|
528
|
+
expect(refs[0]!.collection).toBe('blog-posts');
|
|
529
|
+
expect(refs[0]!.fieldName).toBe('author');
|
|
530
|
+
expect(refs[0]!.itemFilename).toBe('hello-world');
|
|
531
|
+
expect(refs[1]!.itemFilename).toBe('getting-started');
|
|
487
532
|
});
|
|
488
533
|
|
|
489
534
|
it('should find references in multi-reference fields', async () => {
|
|
490
535
|
// hello-world is referenced by 2 posts via 'relatedPosts' field
|
|
491
536
|
const refs = await service.findReferencesTo('blog-posts', 'hello-world');
|
|
492
537
|
expect(refs).toHaveLength(2);
|
|
493
|
-
expect(refs.every(r => r.fieldName === 'relatedPosts')).toBe(true);
|
|
538
|
+
expect(refs.every((r) => r.fieldName === 'relatedPosts')).toBe(true);
|
|
494
539
|
});
|
|
495
540
|
|
|
496
541
|
it('should return empty array when no references exist', async () => {
|
|
497
542
|
// jane-smith is only referenced by advanced-tips
|
|
498
543
|
const refs = await service.findReferencesTo('authors', 'jane-smith');
|
|
499
544
|
expect(refs).toHaveLength(1);
|
|
500
|
-
expect(refs[0]
|
|
545
|
+
expect(refs[0]!.itemFilename).toBe('advanced-tips');
|
|
501
546
|
});
|
|
502
547
|
|
|
503
548
|
it('should return empty array for non-existent item', async () => {
|
|
@@ -510,12 +555,12 @@ describe('CMSService', () => {
|
|
|
510
555
|
// but not products (which has no reference fields to authors)
|
|
511
556
|
const refs = await service.findReferencesTo('authors', 'john-doe');
|
|
512
557
|
// All references should be from blog-posts, not products
|
|
513
|
-
expect(refs.every(r => r.collection === 'blog-posts')).toBe(true);
|
|
558
|
+
expect(refs.every((r) => r.collection === 'blog-posts')).toBe(true);
|
|
514
559
|
});
|
|
515
560
|
|
|
516
561
|
it('should include item metadata in results', async () => {
|
|
517
562
|
const refs = await service.findReferencesTo('authors', 'john-doe');
|
|
518
|
-
const firstRef = refs[0]
|
|
563
|
+
const firstRef = refs[0]!;
|
|
519
564
|
expect(firstRef.itemId).toBe('1');
|
|
520
565
|
expect(firstRef.itemFilename).toBe('hello-world');
|
|
521
566
|
expect(firstRef.itemSlug).toBe('hello-world');
|
|
@@ -543,8 +588,8 @@ describe('CMSService', () => {
|
|
|
543
588
|
expect(savedItems).toHaveLength(2);
|
|
544
589
|
|
|
545
590
|
// Both items should have author set to null
|
|
546
|
-
expect(savedItems[0]
|
|
547
|
-
expect(savedItems[1]
|
|
591
|
+
expect(savedItems[0]!.item.author).toBeNull();
|
|
592
|
+
expect(savedItems[1]!.item.author).toBeNull();
|
|
548
593
|
});
|
|
549
594
|
|
|
550
595
|
it('should filter multi-reference arrays', async () => {
|
|
@@ -554,11 +599,11 @@ describe('CMSService', () => {
|
|
|
554
599
|
expect(removedCount).toBe(2);
|
|
555
600
|
|
|
556
601
|
// getting-started had ['hello-world'] -> should become null (empty array)
|
|
557
|
-
const gettingStarted = savedItems.find(s => s.item._filename === 'getting-started');
|
|
602
|
+
const gettingStarted = savedItems.find((s) => s.item._filename === 'getting-started');
|
|
558
603
|
expect(gettingStarted?.item.relatedPosts).toBeNull();
|
|
559
604
|
|
|
560
605
|
// advanced-tips had ['hello-world', 'getting-started'] -> should become ['getting-started']
|
|
561
|
-
const advancedTips = savedItems.find(s => s.item._filename === 'advanced-tips');
|
|
606
|
+
const advancedTips = savedItems.find((s) => s.item._filename === 'advanced-tips');
|
|
562
607
|
expect(advancedTips?.item.relatedPosts).toEqual(['getting-started']);
|
|
563
608
|
});
|
|
564
609
|
|
|
@@ -566,7 +611,7 @@ describe('CMSService', () => {
|
|
|
566
611
|
// getting-started has relatedPosts: ['hello-world'] - when hello-world is removed, should be null
|
|
567
612
|
await service.removeReferencesTo('blog-posts', 'hello-world');
|
|
568
613
|
|
|
569
|
-
const gettingStarted = savedItems.find(s => s.item._filename === 'getting-started');
|
|
614
|
+
const gettingStarted = savedItems.find((s) => s.item._filename === 'getting-started');
|
|
570
615
|
// Empty array should become null, not []
|
|
571
616
|
expect(gettingStarted?.item.relatedPosts).toBeNull();
|
|
572
617
|
});
|
|
@@ -593,7 +638,7 @@ describe('CMSService', () => {
|
|
|
593
638
|
it('should preserve other item fields', async () => {
|
|
594
639
|
await service.removeReferencesTo('authors', 'john-doe');
|
|
595
640
|
|
|
596
|
-
const helloWorld = savedItems.find(s => s.item._filename === 'hello-world');
|
|
641
|
+
const helloWorld = savedItems.find((s) => s.item._filename === 'hello-world');
|
|
597
642
|
expect(helloWorld?.item._id).toBe('1');
|
|
598
643
|
expect(helloWorld?.item._filename).toBe('hello-world');
|
|
599
644
|
expect(helloWorld?.item.title).toBe('Hello World');
|
|
@@ -653,7 +698,9 @@ describe('CMSService', () => {
|
|
|
653
698
|
hasDraft: async () => false,
|
|
654
699
|
saveDraft: async () => {},
|
|
655
700
|
discardDraft: async () => {},
|
|
656
|
-
publishDraft: async () => {
|
|
701
|
+
publishDraft: async () => {
|
|
702
|
+
throw new Error('not implemented');
|
|
703
|
+
},
|
|
657
704
|
};
|
|
658
705
|
|
|
659
706
|
const richService = new CMSService(richTextProvider);
|
|
@@ -662,7 +709,7 @@ describe('CMSService', () => {
|
|
|
662
709
|
const items = await richService.queryItems({ collection: 'articles' });
|
|
663
710
|
|
|
664
711
|
expect(items).toHaveLength(1);
|
|
665
|
-
const item = items[0]
|
|
712
|
+
const item = items[0]!;
|
|
666
713
|
|
|
667
714
|
// Content should be converted to __richtext__ marker
|
|
668
715
|
expect(item.content).toBeDefined();
|
|
@@ -708,14 +755,16 @@ describe('CMSService', () => {
|
|
|
708
755
|
hasDraft: async () => false,
|
|
709
756
|
saveDraft: async () => {},
|
|
710
757
|
discardDraft: async () => {},
|
|
711
|
-
publishDraft: async () => {
|
|
758
|
+
publishDraft: async () => {
|
|
759
|
+
throw new Error('not implemented');
|
|
760
|
+
},
|
|
712
761
|
};
|
|
713
762
|
|
|
714
763
|
const svc = new CMSService(provider);
|
|
715
764
|
await svc.initialize();
|
|
716
765
|
|
|
717
766
|
const items = await svc.queryItems({ collection: 'articles' });
|
|
718
|
-
const item = items[0]
|
|
767
|
+
const item = items[0]!;
|
|
719
768
|
|
|
720
769
|
expect((item.content as Record<string, unknown>).__richtext__).toBe(true);
|
|
721
770
|
expect((item.content as Record<string, unknown>).html).toBe('<p>Already HTML</p>');
|
|
@@ -736,9 +785,7 @@ describe('CMSService', () => {
|
|
|
736
785
|
pagePath: '/templates/article.json',
|
|
737
786
|
};
|
|
738
787
|
|
|
739
|
-
const mockItems: CMSItem[] = [
|
|
740
|
-
{ _id: '1', _filename: 'test', slug: 'test', summary: 'Plain text summary' },
|
|
741
|
-
];
|
|
788
|
+
const mockItems: CMSItem[] = [{ _id: '1', _filename: 'test', slug: 'test', summary: 'Plain text summary' }];
|
|
742
789
|
|
|
743
790
|
const provider: CMSProvider = {
|
|
744
791
|
getAllSchemas: async () => new Map([['articles', schemaInfo]]),
|
|
@@ -753,7 +800,9 @@ describe('CMSService', () => {
|
|
|
753
800
|
hasDraft: async () => false,
|
|
754
801
|
saveDraft: async () => {},
|
|
755
802
|
discardDraft: async () => {},
|
|
756
|
-
publishDraft: async () => {
|
|
803
|
+
publishDraft: async () => {
|
|
804
|
+
throw new Error('not implemented');
|
|
805
|
+
},
|
|
757
806
|
};
|
|
758
807
|
|
|
759
808
|
const svc = new CMSService(provider);
|
|
@@ -761,7 +810,7 @@ describe('CMSService', () => {
|
|
|
761
810
|
|
|
762
811
|
const items = await svc.queryItems({ collection: 'articles' });
|
|
763
812
|
// Regular text field should remain unchanged
|
|
764
|
-
expect(items[0]
|
|
813
|
+
expect(items[0]!.summary).toBe('Plain text summary');
|
|
765
814
|
});
|
|
766
815
|
|
|
767
816
|
it('should skip null/undefined richtext fields', async () => {
|
|
@@ -797,39 +846,37 @@ describe('CMSService', () => {
|
|
|
797
846
|
hasDraft: async () => false,
|
|
798
847
|
saveDraft: async () => {},
|
|
799
848
|
discardDraft: async () => {},
|
|
800
|
-
publishDraft: async () => {
|
|
849
|
+
publishDraft: async () => {
|
|
850
|
+
throw new Error('not implemented');
|
|
851
|
+
},
|
|
801
852
|
};
|
|
802
853
|
|
|
803
854
|
const svc = new CMSService(provider);
|
|
804
855
|
await svc.initialize();
|
|
805
856
|
|
|
806
857
|
const items = await svc.queryItems({ collection: 'articles' });
|
|
807
|
-
expect(items[0]
|
|
808
|
-
expect(items[1]
|
|
858
|
+
expect(items[0]!.content).toBeNull();
|
|
859
|
+
expect(items[1]!.content).toBeUndefined();
|
|
809
860
|
});
|
|
810
861
|
});
|
|
811
862
|
|
|
812
863
|
describe('drafts', () => {
|
|
813
|
-
function makeService(opts: {
|
|
814
|
-
published?: CMSItem[];
|
|
815
|
-
drafts?: CMSItem[];
|
|
816
|
-
}): CMSService {
|
|
864
|
+
function makeService(opts: { published?: CMSItem[]; drafts?: CMSItem[] }): CMSService {
|
|
817
865
|
const published = opts.published ?? [];
|
|
818
866
|
const drafts = opts.drafts ?? [];
|
|
819
|
-
const findByFilename = (list: CMSItem[], f: string) =>
|
|
820
|
-
list.find(i => i._filename === f) || null;
|
|
867
|
+
const findByFilename = (list: CMSItem[], f: string) => list.find((i) => i._filename === f) || null;
|
|
821
868
|
|
|
822
869
|
const provider: CMSProvider = {
|
|
823
870
|
getAllSchemas: async () => new Map([['blog-posts', mockSchemaInfo]]),
|
|
824
871
|
getItems: async () => published,
|
|
825
872
|
getItemBySlug: async (_c, s) => findByFilename(published, s),
|
|
826
873
|
getItemByFilename: async (_c, f) => findByFilename(published, f),
|
|
827
|
-
getItemById: async (_c, id) => published.find(i => i._id === id) ?? null,
|
|
874
|
+
getItemById: async (_c, id) => published.find((i) => i._id === id) ?? null,
|
|
828
875
|
saveItem: async () => {},
|
|
829
876
|
deleteItem: async () => {},
|
|
830
877
|
getDraft: async (_c, f) => findByFilename(drafts, f),
|
|
831
878
|
getAllDrafts: async () => drafts,
|
|
832
|
-
hasDraft: async (_c, f) => drafts.some(d => d._filename === f),
|
|
879
|
+
hasDraft: async (_c, f) => drafts.some((d) => d._filename === f),
|
|
833
880
|
saveDraft: async () => {},
|
|
834
881
|
discardDraft: async () => {},
|
|
835
882
|
publishDraft: async (_c, f) => {
|
|
@@ -870,15 +917,13 @@ describe('CMSService', () => {
|
|
|
870
917
|
{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello' },
|
|
871
918
|
{ _id: '2', _filename: 'second', slug: 'second', title: 'Second' },
|
|
872
919
|
],
|
|
873
|
-
drafts: [
|
|
874
|
-
{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello (WIP)', _isDraft: true },
|
|
875
|
-
],
|
|
920
|
+
drafts: [{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello (WIP)', _isDraft: true }],
|
|
876
921
|
});
|
|
877
922
|
await svc.initialize();
|
|
878
923
|
const list = await svc.listItemsWithDraftFlag('blog-posts');
|
|
879
924
|
expect(list).toHaveLength(2);
|
|
880
|
-
const hello = list.find(i => i._filename === 'hello');
|
|
881
|
-
const second = list.find(i => i._filename === 'second');
|
|
925
|
+
const hello = list.find((i) => i._filename === 'hello');
|
|
926
|
+
const second = list.find((i) => i._filename === 'second');
|
|
882
927
|
expect(hello?._hasDraft).toBe(true);
|
|
883
928
|
expect(second?._hasDraft).toBeUndefined();
|
|
884
929
|
});
|
|
@@ -886,28 +931,24 @@ describe('CMSService', () => {
|
|
|
886
931
|
it('listItemsWithDraftFlag includes draft-only items at end', async () => {
|
|
887
932
|
const svc = makeService({
|
|
888
933
|
published: [{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello' }],
|
|
889
|
-
drafts: [
|
|
890
|
-
{ _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true },
|
|
891
|
-
],
|
|
934
|
+
drafts: [{ _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true }],
|
|
892
935
|
});
|
|
893
936
|
await svc.initialize();
|
|
894
937
|
const list = await svc.listItemsWithDraftFlag('blog-posts');
|
|
895
938
|
expect(list).toHaveLength(2);
|
|
896
|
-
const draftOnly = list.find(i => i._filename === 'brand-new');
|
|
939
|
+
const draftOnly = list.find((i) => i._filename === 'brand-new');
|
|
897
940
|
expect(draftOnly?._isDraft).toBe(true);
|
|
898
941
|
});
|
|
899
942
|
|
|
900
943
|
it('queryItems is unaffected by drafts (still published-only)', async () => {
|
|
901
944
|
const svc = makeService({
|
|
902
945
|
published: [{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello' }],
|
|
903
|
-
drafts: [
|
|
904
|
-
{ _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true },
|
|
905
|
-
],
|
|
946
|
+
drafts: [{ _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true }],
|
|
906
947
|
});
|
|
907
948
|
await svc.initialize();
|
|
908
949
|
const items = await svc.queryItems({ collection: 'blog-posts' });
|
|
909
950
|
expect(items).toHaveLength(1);
|
|
910
|
-
expect(items[0]
|
|
951
|
+
expect(items[0]!._filename).toBe('hello');
|
|
911
952
|
});
|
|
912
953
|
|
|
913
954
|
it('publishDraft delegates to provider and invalidates cache', async () => {
|
|
@@ -922,30 +963,27 @@ describe('CMSService', () => {
|
|
|
922
963
|
});
|
|
923
964
|
|
|
924
965
|
describe('preview mode', () => {
|
|
925
|
-
function makeService(opts: {
|
|
926
|
-
previewMode?: boolean;
|
|
927
|
-
published?: CMSItem[];
|
|
928
|
-
drafts?: CMSItem[];
|
|
929
|
-
}): CMSService {
|
|
966
|
+
function makeService(opts: { previewMode?: boolean; published?: CMSItem[]; drafts?: CMSItem[] }): CMSService {
|
|
930
967
|
const published = opts.published ?? [];
|
|
931
968
|
const drafts = opts.drafts ?? [];
|
|
932
|
-
const findByFilename = (list: CMSItem[], f: string) =>
|
|
933
|
-
list.find(i => i._filename === f) || null;
|
|
969
|
+
const findByFilename = (list: CMSItem[], f: string) => list.find((i) => i._filename === f) || null;
|
|
934
970
|
|
|
935
971
|
const provider: CMSProvider = {
|
|
936
972
|
getAllSchemas: async () => new Map([['blog-posts', mockSchemaInfo]]),
|
|
937
973
|
getItems: async () => published,
|
|
938
974
|
getItemBySlug: async (_c, s) => findByFilename(published, s),
|
|
939
975
|
getItemByFilename: async (_c, f) => findByFilename(published, f),
|
|
940
|
-
getItemById: async (_c, id) => published.find(i => i._id === id) ?? null,
|
|
976
|
+
getItemById: async (_c, id) => published.find((i) => i._id === id) ?? null,
|
|
941
977
|
saveItem: async () => {},
|
|
942
978
|
deleteItem: async () => {},
|
|
943
979
|
getDraft: async (_c, f) => findByFilename(drafts, f),
|
|
944
980
|
getAllDrafts: async () => drafts,
|
|
945
|
-
hasDraft: async (_c, f) => drafts.some(d => d._filename === f),
|
|
981
|
+
hasDraft: async (_c, f) => drafts.some((d) => d._filename === f),
|
|
946
982
|
saveDraft: async () => {},
|
|
947
983
|
discardDraft: async () => {},
|
|
948
|
-
publishDraft: async () => {
|
|
984
|
+
publishDraft: async () => {
|
|
985
|
+
throw new Error('not used');
|
|
986
|
+
},
|
|
949
987
|
};
|
|
950
988
|
return new CMSService(provider, { previewMode: opts.previewMode });
|
|
951
989
|
}
|
|
@@ -959,8 +997,8 @@ describe('CMSService', () => {
|
|
|
959
997
|
await svc.initialize();
|
|
960
998
|
const items = await svc.queryItems({ collection: 'blog-posts' });
|
|
961
999
|
expect(items).toHaveLength(1);
|
|
962
|
-
expect(items[0]
|
|
963
|
-
expect(items[0]
|
|
1000
|
+
expect(items[0]!.title).toBe('Hello (WIP)');
|
|
1001
|
+
expect(items[0]!._isDraft).toBe(true);
|
|
964
1002
|
});
|
|
965
1003
|
|
|
966
1004
|
it('queryItems includes draft-only items in preview mode', async () => {
|
|
@@ -972,7 +1010,7 @@ describe('CMSService', () => {
|
|
|
972
1010
|
await svc.initialize();
|
|
973
1011
|
const items = await svc.queryItems({ collection: 'blog-posts' });
|
|
974
1012
|
expect(items).toHaveLength(2);
|
|
975
|
-
expect(items.find(i => i._filename === 'brand-new')?._isDraft).toBe(true);
|
|
1013
|
+
expect(items.find((i) => i._filename === 'brand-new')?._isDraft).toBe(true);
|
|
976
1014
|
});
|
|
977
1015
|
|
|
978
1016
|
it('getItemsByIds merges drafts in preview mode', async () => {
|
|
@@ -1003,7 +1041,7 @@ describe('CMSService', () => {
|
|
|
1003
1041
|
expect(versions.draft?.title).toBe('Hello (WIP)');
|
|
1004
1042
|
|
|
1005
1043
|
const list = await svc.listItemsWithDraftFlag('blog-posts');
|
|
1006
|
-
const item = list.find(i => i._filename === 'hello');
|
|
1044
|
+
const item = list.find((i) => i._filename === 'hello');
|
|
1007
1045
|
expect(item?.title).toBe('Hello');
|
|
1008
1046
|
expect(item?._hasDraft).toBe(true);
|
|
1009
1047
|
});
|
|
@@ -1019,8 +1057,8 @@ describe('CMSService', () => {
|
|
|
1019
1057
|
await svc.initialize();
|
|
1020
1058
|
const items = await svc.queryItems({ collection: 'blog-posts' });
|
|
1021
1059
|
expect(items).toHaveLength(1);
|
|
1022
|
-
expect(items[0]
|
|
1023
|
-
expect(items[0]
|
|
1060
|
+
expect(items[0]!.title).toBe('Hello');
|
|
1061
|
+
expect(items[0]!._isDraft).toBeUndefined();
|
|
1024
1062
|
});
|
|
1025
1063
|
});
|
|
1026
1064
|
});
|