meno-core 1.0.53 → 1.0.54
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 +48 -57
- package/build-astro.ts +131 -113
- package/build-next.ts +109 -96
- package/build-static.test.ts +39 -10
- package/build-static.ts +120 -122
- package/dist/bin/cli.js +34 -38
- package/dist/bin/cli.js.map +2 -2
- package/dist/build-static.js +12 -11
- package/dist/chunks/chunk-2AR55GYH.js +42 -0
- package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
- package/dist/chunks/{chunk-IGYR22T6.js → chunk-2FN4UOVO.js} +512 -239
- package/dist/chunks/chunk-2FN4UOVO.js.map +7 -0
- package/dist/chunks/chunk-3XER4E5W.js +168 -0
- package/dist/chunks/chunk-3XER4E5W.js.map +7 -0
- package/dist/chunks/{chunk-X754AHS5.js → chunk-5ETZFREW.js} +9 -12
- package/dist/chunks/chunk-5ETZFREW.js.map +7 -0
- package/dist/chunks/{chunk-2MHDV5BF.js → chunk-7E4IF5L7.js} +15 -21
- package/dist/chunks/chunk-7E4IF5L7.js.map +7 -0
- package/dist/chunks/{chunk-JGWFTO6P.js → chunk-7HWQUVTU.js} +1578 -1349
- package/dist/chunks/chunk-7HWQUVTU.js.map +7 -0
- package/dist/chunks/{chunk-O3NAGJP4.js → chunk-AE3QK5QW.js} +110 -21
- package/dist/chunks/chunk-AE3QK5QW.js.map +7 -0
- package/dist/chunks/{chunk-GZHGVVW3.js → chunk-F6KTJYGV.js} +7 -7
- package/dist/chunks/chunk-F6KTJYGV.js.map +7 -0
- package/dist/chunks/{chunk-WQFG7PAH.js → chunk-FZITJSSS.js} +2 -6
- package/dist/chunks/chunk-FZITJSSS.js.map +7 -0
- package/dist/chunks/{chunk-QB2LNO4W.js → chunk-GSYYA5GX.js} +2 -2
- package/dist/chunks/chunk-GSYYA5GX.js.map +7 -0
- package/dist/chunks/{chunk-YBLHKYFF.js → chunk-HIZMY3EP.js} +1 -1
- package/dist/chunks/chunk-HIZMY3EP.js.map +7 -0
- package/dist/chunks/{chunk-AZQYF6KE.js → chunk-I2WEGYA7.js} +41 -176
- package/dist/chunks/chunk-I2WEGYA7.js.map +7 -0
- package/dist/chunks/{chunk-I7YIGZXT.js → chunk-JNO3CNLJ.js} +6 -9
- package/dist/chunks/chunk-JNO3CNLJ.js.map +7 -0
- package/dist/chunks/{chunk-UB44F4Z2.js → chunk-NVRBTSQG.js} +2 -4
- package/dist/chunks/chunk-NVRBTSQG.js.map +7 -0
- package/dist/chunks/{chunk-JGP5A3Y5.js → chunk-Q4OBWKXG.js} +40 -33
- package/dist/chunks/chunk-Q4OBWKXG.js.map +7 -0
- package/dist/chunks/{chunk-R6XHAFBF.js → chunk-QTE32Y53.js} +250 -242
- package/dist/chunks/chunk-QTE32Y53.js.map +7 -0
- package/dist/chunks/{chunk-H3GJ4H2U.js → chunk-STDY3OVM.js} +214 -85
- package/dist/chunks/chunk-STDY3OVM.js.map +7 -0
- package/dist/chunks/configService-PRJZF7Y6.js +14 -0
- package/dist/chunks/{constants-STK2YBIW.js → constants-KIQEYMAM.js} +2 -2
- package/dist/chunks/{fs-JGINUXGL.js → fs-ZI5JEU7V.js} +2 -2
- package/dist/entries/server-router.js +14 -19
- package/dist/entries/server-router.js.map +2 -2
- package/dist/lib/client/index.js +638 -332
- package/dist/lib/client/index.js.map +2 -2
- package/dist/lib/server/index.js +177 -235
- package/dist/lib/server/index.js.map +2 -2
- package/dist/lib/shared/index.js +80 -44
- package/dist/lib/shared/index.js.map +2 -2
- package/dist/lib/shared/richtext/index.js +1 -1
- package/dist/lib/test-utils/index.js +38 -60
- package/dist/lib/test-utils/index.js.map +2 -2
- package/entries/client-router.tsx +10 -8
- package/entries/server-router.tsx +1 -7
- package/lib/client/ClientInitializer.ts +8 -8
- package/lib/client/ErrorBoundary.test.tsx +146 -143
- package/lib/client/ErrorBoundary.tsx +175 -127
- package/lib/client/componentRegistry.test.ts +96 -108
- package/lib/client/componentRegistry.ts +1 -2
- package/lib/client/contexts/ThemeContext.tsx +3 -2
- package/lib/client/core/ComponentBuilder.test.ts +513 -560
- package/lib/client/core/ComponentBuilder.ts +318 -146
- package/lib/client/core/ComponentRenderer.test.tsx +1 -2
- package/lib/client/core/ComponentRenderer.tsx +46 -33
- package/lib/client/core/builders/embedBuilder.ts +241 -53
- package/lib/client/core/builders/linkBuilder.ts +71 -44
- package/lib/client/core/builders/linkNodeBuilder.ts +78 -53
- package/lib/client/core/builders/listBuilder.ts +115 -86
- package/lib/client/core/builders/localeListBuilder.ts +95 -60
- package/lib/client/core/builders/types.ts +5 -5
- package/lib/client/core/cmsTemplateProcessor.ts +7 -7
- 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 +8 -0
- package/lib/client/hmrCssReload.ts +14 -8
- package/lib/client/hmrWebSocket.ts +9 -14
- package/lib/client/hooks/useColorVariables.test.ts +21 -21
- package/lib/client/hooks/useColorVariables.ts +12 -10
- package/lib/client/hooks/usePropertyAutocomplete.ts +3 -5
- package/lib/client/hooks/useVariables.ts +4 -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 +19 -21
- package/lib/client/meno-filter/MenoFilter.ts +5 -9
- package/lib/client/meno-filter/bindings.ts +15 -40
- package/lib/client/meno-filter/init.ts +1 -1
- package/lib/client/meno-filter/renderer.ts +23 -29
- package/lib/client/meno-filter/script.generated.ts +1 -3
- package/lib/client/meno-filter/ui.ts +3 -5
- package/lib/client/meno-filter/updates.ts +15 -21
- package/lib/client/navigation.test.ts +159 -159
- package/lib/client/navigation.ts +0 -1
- package/lib/client/responsiveStyleResolver.test.ts +230 -228
- package/lib/client/responsiveStyleResolver.ts +13 -16
- package/lib/client/routing/RouteLoader.test.ts +23 -24
- package/lib/client/routing/RouteLoader.ts +22 -35
- package/lib/client/routing/Router.tsx +31 -3
- package/lib/client/scripts/ScriptExecutor.test.ts +157 -158
- package/lib/client/scripts/ScriptExecutor.ts +15 -33
- package/lib/client/services/PrefetchService.test.ts +2 -2
- package/lib/client/services/PrefetchService.ts +10 -24
- package/lib/client/styleProcessor.test.ts +9 -9
- package/lib/client/styleProcessor.ts +18 -15
- package/lib/client/styles/StyleInjector.test.ts +122 -115
- package/lib/client/styles/StyleInjector.ts +9 -6
- package/lib/client/styles/UtilityClassCollector.ts +19 -26
- package/lib/client/styles/cspNonce.test.ts +2 -5
- package/lib/client/templateEngine.test.ts +554 -482
- package/lib/client/templateEngine.ts +200 -64
- 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 +2 -5
- package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
- package/lib/server/__integration__/static-assets.test.ts +1 -1
- package/lib/server/__integration__/test-helpers.ts +84 -70
- package/lib/server/ab/generateFunctions.ts +12 -10
- package/lib/server/astro/cmsPageEmitter.ts +23 -38
- package/lib/server/astro/componentEmitter.ts +25 -36
- package/lib/server/astro/cssCollector.ts +10 -26
- package/lib/server/astro/nodeToAstro.test.ts +1750 -30
- package/lib/server/astro/nodeToAstro.ts +198 -187
- package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +105 -109
- package/lib/server/astro/normalizeOrphanTemplateProps.ts +4 -12
- 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 +14 -17
- package/lib/server/createServer.ts +5 -17
- package/lib/server/cssGenerator.test.ts +35 -44
- package/lib/server/cssGenerator.ts +6 -17
- package/lib/server/fileWatcher.test.ts +124 -10
- package/lib/server/fileWatcher.ts +124 -118
- package/lib/server/index.ts +7 -1
- package/lib/server/jsonLoader.test.ts +39 -2
- package/lib/server/jsonLoader.ts +33 -31
- package/lib/server/middleware/cors.test.ts +20 -20
- package/lib/server/middleware/cors.ts +28 -4
- package/lib/server/middleware/errorHandler.test.ts +5 -3
- package/lib/server/middleware/errorHandler.ts +3 -8
- package/lib/server/middleware/index.ts +0 -1
- package/lib/server/middleware/logger.test.ts +7 -5
- package/lib/server/middleware/logger.ts +10 -22
- package/lib/server/pageCache.test.ts +76 -77
- package/lib/server/pageCache.ts +0 -1
- package/lib/server/projectContext.ts +4 -3
- package/lib/server/providers/fileSystemCMSProvider.test.ts +124 -95
- package/lib/server/providers/fileSystemCMSProvider.ts +35 -20
- package/lib/server/providers/fileSystemPageProvider.test.ts +84 -0
- package/lib/server/providers/fileSystemPageProvider.ts +31 -12
- package/lib/server/routes/api/cms.test.ts +26 -14
- package/lib/server/routes/api/cms.ts +9 -14
- package/lib/server/routes/api/components.ts +30 -34
- package/lib/server/routes/api/config.ts +0 -1
- package/lib/server/routes/api/core-routes.ts +47 -74
- package/lib/server/routes/api/functions.ts +8 -16
- 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 +1 -3
- package/lib/server/routes/api/variables.ts +1 -1
- package/lib/server/routes/index.ts +23 -26
- package/lib/server/routes/pages.ts +34 -29
- package/lib/server/routes/static.ts +16 -4
- package/lib/server/runtime/bundler.ts +47 -32
- package/lib/server/runtime/fs.ts +3 -13
- package/lib/server/runtime/httpServer.ts +5 -9
- package/lib/server/services/ColorService.ts +32 -27
- package/lib/server/services/EnumService.test.ts +2 -6
- package/lib/server/services/EnumService.ts +7 -2
- package/lib/server/services/VariableService.test.ts +1 -5
- package/lib/server/services/VariableService.ts +6 -1
- package/lib/server/services/cmsService.test.ts +116 -78
- package/lib/server/services/cmsService.ts +24 -54
- package/lib/server/services/componentService.test.ts +122 -36
- package/lib/server/services/componentService.ts +54 -38
- package/lib/server/services/configService.test.ts +9 -31
- package/lib/server/services/configService.ts +20 -27
- package/lib/server/services/fileWatcherService.ts +40 -6
- package/lib/server/services/index.ts +0 -1
- package/lib/server/services/pageService.test.ts +1 -3
- package/lib/server/services/pageService.ts +14 -13
- package/lib/server/ssr/attributeBuilder.ts +16 -6
- package/lib/server/ssr/buildErrorOverlay.ts +11 -12
- package/lib/server/ssr/clientDataInjector.ts +7 -21
- package/lib/server/ssr/cmsSSRProcessor.ts +3 -6
- 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 +3 -9
- package/lib/server/ssr/htmlGenerator.test.ts +120 -43
- package/lib/server/ssr/htmlGenerator.ts +120 -85
- package/lib/server/ssr/imageMetadata.test.ts +3 -1
- package/lib/server/ssr/imageMetadata.ts +25 -19
- package/lib/server/ssr/jsCollector.test.ts +3 -13
- package/lib/server/ssr/jsCollector.ts +3 -8
- package/lib/server/ssr/liveReloadIntegration.test.ts +69 -28
- 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 +196 -246
- package/lib/server/ssr/ssrRenderer.ts +609 -225
- package/lib/server/ssrRenderer.test.ts +1044 -950
- package/lib/server/utils/jsonLineMapper.test.ts +28 -28
- package/lib/server/utils/jsonLineMapper.ts +1 -1
- package/lib/server/validateStyleCoverage.ts +18 -20
- package/lib/server/webflow/buildWebflow.ts +41 -53
- package/lib/server/webflow/nodeToWebflow.test.ts +150 -218
- package/lib/server/webflow/nodeToWebflow.ts +195 -258
- package/lib/server/webflow/styleMapper.test.ts +15 -56
- package/lib/server/webflow/styleMapper.ts +33 -41
- package/lib/server/webflow/types.ts +1 -8
- package/lib/server/websocketManager.ts +16 -19
- package/lib/shared/attributeNodeUtils.test.ts +15 -15
- package/lib/shared/attributeNodeUtils.ts +5 -12
- package/lib/shared/breakpoints.ts +4 -11
- package/lib/shared/cmsQueryParser.test.ts +50 -42
- package/lib/shared/cmsQueryParser.ts +49 -31
- package/lib/shared/colorVariableUtils.test.ts +5 -5
- package/lib/shared/colorVariableUtils.ts +3 -8
- package/lib/shared/componentRefs.ts +1 -5
- package/lib/shared/constants.test.ts +3 -3
- package/lib/shared/constants.ts +4 -8
- package/lib/shared/cssGeneration.test.ts +262 -144
- package/lib/shared/cssGeneration.ts +189 -516
- package/lib/shared/cssNamedColors.ts +152 -30
- package/lib/shared/cssProperties.test.ts +5 -6
- package/lib/shared/cssProperties.ts +296 -112
- package/lib/shared/elementClassName.test.ts +109 -109
- package/lib/shared/elementClassName.ts +1 -1
- package/lib/shared/elementUtils.ts +12 -16
- 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 +119 -0
- package/lib/shared/expressionEvaluator.ts +43 -24
- package/lib/shared/fontLoader.test.ts +19 -5
- package/lib/shared/friendlyError.ts +2 -3
- package/lib/shared/gradientUtils.test.ts +1 -5
- package/lib/shared/gradientUtils.ts +2 -6
- package/lib/shared/hrefRefs.ts +2 -10
- package/lib/shared/i18n.test.ts +1 -1
- package/lib/shared/i18n.ts +13 -34
- package/lib/shared/index.ts +4 -0
- package/lib/shared/inlineSvgStyleRules.ts +2 -4
- package/lib/shared/interactiveStyleMappings.test.ts +11 -33
- package/lib/shared/interactiveStyleMappings.ts +9 -16
- package/lib/shared/interactiveStyles.test.ts +165 -188
- package/lib/shared/interfaces/contentProvider.ts +1 -1
- package/lib/shared/itemTemplateUtils.test.ts +6 -12
- package/lib/shared/itemTemplateUtils.ts +19 -35
- package/lib/shared/jsonRepair.ts +8 -2
- package/lib/shared/libraryLoader.test.ts +15 -49
- package/lib/shared/libraryLoader.ts +7 -22
- package/lib/shared/netlifyLocale404.test.ts +179 -0
- package/lib/shared/netlifyLocale404.ts +110 -0
- package/lib/shared/nodeUtils.test.ts +24 -16
- package/lib/shared/nodeUtils.ts +49 -19
- package/lib/shared/pathArrayUtils.test.ts +1 -2
- package/lib/shared/pathArrayUtils.ts +1 -1
- package/lib/shared/pathSecurity.ts +1 -1
- package/lib/shared/pathUtils.test.ts +4 -6
- package/lib/shared/pathUtils.ts +42 -48
- 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 +14 -17
- package/lib/shared/paths/PathUtils.ts +9 -10
- package/lib/shared/paths/PathValidator.test.ts +2 -15
- package/lib/shared/paths/PathValidator.ts +11 -9
- package/lib/shared/paths/index.ts +1 -2
- package/lib/shared/propResolver.test.ts +240 -244
- package/lib/shared/propResolver.ts +14 -25
- package/lib/shared/pxToRem.test.ts +7 -6
- package/lib/shared/pxToRem.ts +2 -5
- package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +9 -5
- package/lib/shared/registry/ClientRegistry.ts +0 -1
- package/lib/shared/registry/ComponentRegistry.test.ts +43 -29
- package/lib/shared/registry/ComponentRegistry.ts +9 -11
- package/lib/shared/registry/NodeTypeDefinition.ts +15 -8
- package/lib/shared/registry/RegistryManager.ts +1 -2
- package/lib/shared/registry/SSRRegistry.ts +0 -1
- package/lib/shared/registry/createNodeType.ts +7 -9
- package/lib/shared/registry/defineNodeType.ts +2 -6
- package/lib/shared/registry/index.ts +0 -1
- package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
- package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
- package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +47 -18
- package/lib/shared/registry/nodeTypes/LinkNodeType.ts +21 -19
- package/lib/shared/registry/nodeTypes/ListNodeType.ts +78 -74
- package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
- package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +6 -7
- package/lib/shared/registry/nodeTypes/index.ts +10 -2
- package/lib/shared/responsiveScaling.test.ts +15 -31
- package/lib/shared/responsiveScaling.ts +55 -37
- package/lib/shared/responsiveStyleUtils.ts +11 -13
- package/lib/shared/richtext/htmlToTiptap.test.ts +23 -14
- package/lib/shared/richtext/htmlToTiptap.ts +1 -3
- 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 +5 -10
- package/lib/shared/styleUtils.test.ts +87 -61
- package/lib/shared/styleUtils.ts +5 -6
- package/lib/shared/themeDefaults.test.ts +11 -11
- package/lib/shared/themeDefaults.ts +3 -4
- package/lib/shared/tree/PathBuilder.test.ts +62 -138
- package/lib/shared/tree/PathBuilder.ts +49 -39
- package/lib/shared/treePathUtils.test.ts +2 -10
- package/lib/shared/treePathUtils.ts +54 -59
- package/lib/shared/types/api.ts +1 -2
- package/lib/shared/types/cms.ts +25 -21
- package/lib/shared/types/comment.ts +49 -16
- package/lib/shared/types/components.ts +27 -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 +2 -2
- package/lib/shared/types/styles.ts +0 -1
- package/lib/shared/types/variables.test.ts +4 -13
- package/lib/shared/types/variables.ts +48 -27
- package/lib/shared/types.ts +1 -2
- package/lib/shared/utilityClassConfig.ts +648 -321
- package/lib/shared/utilityClassMapper.test.ts +203 -92
- package/lib/shared/utilityClassMapper.ts +188 -246
- package/lib/shared/utilityClassNames.ts +326 -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/propValidator.test.ts +18 -20
- package/lib/shared/validation/propValidator.ts +12 -17
- package/lib/shared/validation/schemas.test.ts +24 -33
- package/lib/shared/validation/schemas.ts +469 -344
- package/lib/shared/validation/validators.test.ts +1 -6
- package/lib/shared/validation/validators.ts +89 -68
- package/lib/shared/viewportUnits.integration.test.ts +14 -10
- package/lib/shared/viewportUnits.test.ts +11 -23
- package/lib/test-utils/dom-setup.ts +1 -1
- package/lib/test-utils/factories/ConsoleMockFactory.ts +3 -7
- package/lib/test-utils/factories/DomMockFactory.ts +7 -19
- 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 +5 -9
- package/lib/test-utils/factories/StoreMockFactory.ts +14 -25
- 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 +12 -18
- package/lib/test-utils/mocks.ts +4 -2
- package/package.json +1 -1
- package/scripts/build-meno-filter.ts +1 -4
- package/vite.config.ts +4 -4
- package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
- package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
- package/dist/chunks/chunk-GZHGVVW3.js.map +0 -7
- package/dist/chunks/chunk-H3GJ4H2U.js.map +0 -7
- package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
- package/dist/chunks/chunk-IGYR22T6.js.map +0 -7
- 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.map +0 -7
- 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 → configService-PRJZF7Y6.js.map} +0 -0
- /package/dist/chunks/{constants-STK2YBIW.js.map → constants-KIQEYMAM.js.map} +0 -0
- /package/dist/chunks/{fs-JGINUXGL.js.map → fs-ZI5JEU7V.js.map} +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale-scoped Netlify 404 rules + the managed netlify.toml block that carries them.
|
|
3
|
+
*
|
|
4
|
+
* Why: a multi-locale static build emits a localized 404 per non-default locale
|
|
5
|
+
* (`dist/pl/404/index.html`), but a static host serves exactly ONE catch-all 404
|
|
6
|
+
* page unless told otherwise — so `/pl/<missing>` would get the default-locale
|
|
7
|
+
* `404.html`. These rules scope the 404 per locale prefix.
|
|
8
|
+
*
|
|
9
|
+
* Shared by every netlify.toml producer — meno-astro's `convertProject` scaffold,
|
|
10
|
+
* the JSON→Astro export (`build-astro.ts`), the CLI new-project scaffold — and by
|
|
11
|
+
* the studio save-config route, which re-syncs the managed block when the locale
|
|
12
|
+
* set changes AFTER the file was first written (so a project that adds a locale
|
|
13
|
+
* later still gets its rules). It lives in meno-core because the dependency
|
|
14
|
+
* direction is astro→core: meno-core must never import from meno-astro.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { I18nConfig } from './types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* First line of the managed block. Everything between the markers (inclusive) is
|
|
21
|
+
* generated and may be rewritten wholesale by `syncNetlifyLocale404Block`; user
|
|
22
|
+
* content outside the markers is never touched.
|
|
23
|
+
*/
|
|
24
|
+
export const NETLIFY_LOCALE_404_BEGIN = '# BEGIN meno locale-404 redirects (generated — do not edit between markers)';
|
|
25
|
+
|
|
26
|
+
/** Last line of the managed block. */
|
|
27
|
+
export const NETLIFY_LOCALE_404_END = '# END meno locale-404 redirects';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Locale-scoped 404 rules for a netlify.toml — one `[[redirects]]` block per
|
|
31
|
+
* non-default locale (`''` for single-locale configs):
|
|
32
|
+
*
|
|
33
|
+
* [[redirects]]
|
|
34
|
+
* from = "/pl/*"
|
|
35
|
+
* to = "/pl/404/index.html"
|
|
36
|
+
* status = 404
|
|
37
|
+
*
|
|
38
|
+
* Netlify semantics (verified against Netlify's "redirect options" docs, the
|
|
39
|
+
* documented "localized custom 404" pattern): a redirect with `status = 404` and no
|
|
40
|
+
* `force` is a NON-SHADOWING rewrite — a request that matches an existing file is
|
|
41
|
+
* served normally (real `/pl/...` pages always win), and only an unmatched `/pl/*`
|
|
42
|
+
* URL serves the `to` file's CONTENT with an HTTP 404 status (the URL stays put; no
|
|
43
|
+
* 3xx). Everything the rules don't cover falls through to Netlify's root convention:
|
|
44
|
+
* a top-level `404.html` (which Astro builds from `src/pages/404.astro`) is served
|
|
45
|
+
* automatically for any other unmatched URL — no explicit catch-all rule needed.
|
|
46
|
+
*
|
|
47
|
+
* Locale codes are sanity-checked (`/^[A-Za-z0-9_-]+$/`): a malformed code would
|
|
48
|
+
* corrupt the TOML / redirect syntax, and such a locale cannot produce a route anyway.
|
|
49
|
+
*
|
|
50
|
+
* Pure (config in, TOML fragment out) so it is directly unit-testable; callers own
|
|
51
|
+
* the existence gates (404 page present, netlify.toml ownership). Most callers
|
|
52
|
+
* should go through `syncNetlifyLocale404Block`, which wraps the rules in the
|
|
53
|
+
* managed marker block so later config saves can update them in place.
|
|
54
|
+
*/
|
|
55
|
+
export function netlifyLocale404Redirects(config: I18nConfig): string {
|
|
56
|
+
if (!config.locales || config.locales.length <= 1) return '';
|
|
57
|
+
const codes = config.locales
|
|
58
|
+
.map((l) => l.code)
|
|
59
|
+
.filter((code) => code !== config.defaultLocale && /^[A-Za-z0-9_-]+$/.test(code));
|
|
60
|
+
if (codes.length === 0) return '';
|
|
61
|
+
const header =
|
|
62
|
+
"\n# Locale-scoped 404s — an unmatched /<locale>/* URL serves that locale's own\n" +
|
|
63
|
+
'# prerendered 404 page WITH a 404 status (non-shadowing: real pages still win).\n' +
|
|
64
|
+
'# Unmatched URLs outside these prefixes fall through to the default /404.html.\n';
|
|
65
|
+
const rules = codes
|
|
66
|
+
.map((code) => `[[redirects]]\n from = "/${code}/*"\n to = "/${code}/404/index.html"\n status = 404\n`)
|
|
67
|
+
.join('\n');
|
|
68
|
+
return header + rules;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Insert / refresh / remove the managed locale-404 block in netlify.toml content.
|
|
73
|
+
* Pure (string in, string out) — callers own reading/writing the file.
|
|
74
|
+
*
|
|
75
|
+
* - Rules applicable (multi-locale config AND `has404`) + no block yet → the block
|
|
76
|
+
* is APPENDED (a trailing newline is added to the existing content first if it
|
|
77
|
+
* lacks one).
|
|
78
|
+
* - Rules applicable + block present → the block's contents are REPLACED in place
|
|
79
|
+
* (idempotent: re-syncing identical state is a no-op).
|
|
80
|
+
* - Rules no longer applicable (single-locale, or no 404 page) + block present →
|
|
81
|
+
* the whole block is REMOVED; everything outside the markers stays byte-identical.
|
|
82
|
+
* - Nothing applicable + no block → the content is returned unchanged.
|
|
83
|
+
*
|
|
84
|
+
* A corrupted block (BEGIN marker without its END) is left untouched — rewriting up
|
|
85
|
+
* to an unknown boundary could eat user content, and a hand-damaged block is the
|
|
86
|
+
* user taking ownership.
|
|
87
|
+
*/
|
|
88
|
+
export function syncNetlifyLocale404Block(content: string, config: I18nConfig, has404: boolean): string {
|
|
89
|
+
const rules = has404 ? netlifyLocale404Redirects(config) : '';
|
|
90
|
+
// `rules` starts with '\n' (terminating the BEGIN line) and ends with '\n'
|
|
91
|
+
// (putting END at line start), so the block is exactly BEGIN…rules…END lines.
|
|
92
|
+
const block = rules ? `${NETLIFY_LOCALE_404_BEGIN}${rules}${NETLIFY_LOCALE_404_END}\n` : '';
|
|
93
|
+
|
|
94
|
+
const beginIdx = content.indexOf(NETLIFY_LOCALE_404_BEGIN);
|
|
95
|
+
if (beginIdx === -1) {
|
|
96
|
+
if (!block) return content;
|
|
97
|
+
const base = content === '' || content.endsWith('\n') ? content : `${content}\n`;
|
|
98
|
+
return base + block;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const endMarkerIdx = content.indexOf(NETLIFY_LOCALE_404_END, beginIdx);
|
|
102
|
+
if (endMarkerIdx === -1) return content; // corrupted block — refuse to guess its extent
|
|
103
|
+
|
|
104
|
+
let endIdx = endMarkerIdx + NETLIFY_LOCALE_404_END.length;
|
|
105
|
+
if (content[endIdx] === '\n') endIdx += 1; // the END line's own newline belongs to the block
|
|
106
|
+
|
|
107
|
+
const before = content.slice(0, beginIdx);
|
|
108
|
+
const after = content.slice(endIdx);
|
|
109
|
+
return before + block + after;
|
|
110
|
+
}
|
|
@@ -24,7 +24,15 @@ import {
|
|
|
24
24
|
isEmptyContainer,
|
|
25
25
|
} from './nodeUtils';
|
|
26
26
|
import { NODE_TYPE } from './constants';
|
|
27
|
-
import type {
|
|
27
|
+
import type {
|
|
28
|
+
ComponentNode,
|
|
29
|
+
ComponentInstanceNode,
|
|
30
|
+
HtmlNode,
|
|
31
|
+
SlotMarker,
|
|
32
|
+
EmbedNode,
|
|
33
|
+
LinkNode,
|
|
34
|
+
LocaleListNode,
|
|
35
|
+
} from './types';
|
|
28
36
|
import { registerBuiltInNodeTypes } from './registry';
|
|
29
37
|
|
|
30
38
|
describe('nodeUtils', () => {
|
|
@@ -126,11 +134,11 @@ describe('nodeUtils', () => {
|
|
|
126
134
|
const node: ComponentInstanceNode = {
|
|
127
135
|
type: NODE_TYPE.COMPONENT,
|
|
128
136
|
component: 'Button',
|
|
129
|
-
props: { text: 'Click me' }
|
|
137
|
+
props: { text: 'Click me' },
|
|
130
138
|
};
|
|
131
139
|
expect(extractNodeProperties(node)).toEqual({
|
|
132
140
|
componentName: 'Button',
|
|
133
|
-
props: { text: 'Click me' }
|
|
141
|
+
props: { text: 'Click me' },
|
|
134
142
|
});
|
|
135
143
|
});
|
|
136
144
|
|
|
@@ -138,7 +146,7 @@ describe('nodeUtils', () => {
|
|
|
138
146
|
const node: HtmlNode = { type: NODE_TYPE.NODE, tag: 'div' };
|
|
139
147
|
expect(extractNodeProperties(node)).toEqual({
|
|
140
148
|
tag: 'div',
|
|
141
|
-
props: {}
|
|
149
|
+
props: {},
|
|
142
150
|
});
|
|
143
151
|
});
|
|
144
152
|
|
|
@@ -328,7 +336,7 @@ describe('nodeUtils', () => {
|
|
|
328
336
|
const mapping = {
|
|
329
337
|
_mapping: true,
|
|
330
338
|
prop: 'visible',
|
|
331
|
-
values: {
|
|
339
|
+
values: { true: true, false: false },
|
|
332
340
|
};
|
|
333
341
|
expect(isBooleanMapping(mapping)).toBe(true);
|
|
334
342
|
});
|
|
@@ -368,8 +376,8 @@ describe('nodeUtils', () => {
|
|
|
368
376
|
if: {
|
|
369
377
|
_mapping: true,
|
|
370
378
|
prop: 'showBanner',
|
|
371
|
-
values: {
|
|
372
|
-
}
|
|
379
|
+
values: { true: true, false: false },
|
|
380
|
+
},
|
|
373
381
|
} as any;
|
|
374
382
|
|
|
375
383
|
expect(evaluateNodeIf(node, { showBanner: 'true' })).toBe(true);
|
|
@@ -383,8 +391,8 @@ describe('nodeUtils', () => {
|
|
|
383
391
|
if: {
|
|
384
392
|
_mapping: true,
|
|
385
393
|
prop: 'status',
|
|
386
|
-
values: {
|
|
387
|
-
}
|
|
394
|
+
values: { active: true, inactive: false },
|
|
395
|
+
},
|
|
388
396
|
} as any;
|
|
389
397
|
|
|
390
398
|
// 'unknown' is not in the values map
|
|
@@ -398,8 +406,8 @@ describe('nodeUtils', () => {
|
|
|
398
406
|
if: {
|
|
399
407
|
_mapping: true,
|
|
400
408
|
prop: 'visible',
|
|
401
|
-
values: {
|
|
402
|
-
}
|
|
409
|
+
values: { true: true, false: false },
|
|
410
|
+
},
|
|
403
411
|
} as any;
|
|
404
412
|
|
|
405
413
|
expect(evaluateNodeIf(node)).toBe(true);
|
|
@@ -409,7 +417,7 @@ describe('nodeUtils', () => {
|
|
|
409
417
|
const node = {
|
|
410
418
|
type: NODE_TYPE.NODE,
|
|
411
419
|
tag: 'div',
|
|
412
|
-
if: '{{showBanner}}'
|
|
420
|
+
if: '{{showBanner}}',
|
|
413
421
|
} as any;
|
|
414
422
|
|
|
415
423
|
// String templates can't be resolved without context, default to true
|
|
@@ -420,7 +428,7 @@ describe('nodeUtils', () => {
|
|
|
420
428
|
const node: ComponentInstanceNode = {
|
|
421
429
|
type: NODE_TYPE.COMPONENT,
|
|
422
430
|
component: 'Banner',
|
|
423
|
-
if: false
|
|
431
|
+
if: false,
|
|
424
432
|
} as any;
|
|
425
433
|
expect(evaluateNodeIf(node)).toBe(false);
|
|
426
434
|
});
|
|
@@ -429,7 +437,7 @@ describe('nodeUtils', () => {
|
|
|
429
437
|
const node: EmbedNode = {
|
|
430
438
|
type: NODE_TYPE.EMBED,
|
|
431
439
|
html: '<svg></svg>',
|
|
432
|
-
if: false
|
|
440
|
+
if: false,
|
|
433
441
|
} as any;
|
|
434
442
|
expect(evaluateNodeIf(node)).toBe(false);
|
|
435
443
|
});
|
|
@@ -438,7 +446,7 @@ describe('nodeUtils', () => {
|
|
|
438
446
|
const node: LinkNode = {
|
|
439
447
|
type: NODE_TYPE.LINK,
|
|
440
448
|
href: '/page',
|
|
441
|
-
if: true
|
|
449
|
+
if: true,
|
|
442
450
|
} as any;
|
|
443
451
|
expect(evaluateNodeIf(node)).toBe(true);
|
|
444
452
|
});
|
|
@@ -515,7 +523,7 @@ describe('nodeUtils', () => {
|
|
|
515
523
|
const node: HtmlNode = {
|
|
516
524
|
type: NODE_TYPE.NODE,
|
|
517
525
|
tag: 'div',
|
|
518
|
-
children: [{ type: NODE_TYPE.NODE, tag: 'span' }]
|
|
526
|
+
children: [{ type: NODE_TYPE.NODE, tag: 'span' }],
|
|
519
527
|
};
|
|
520
528
|
expect(isEmptyContainer(node)).toBe(false);
|
|
521
529
|
});
|
package/lib/shared/nodeUtils.ts
CHANGED
|
@@ -3,7 +3,17 @@
|
|
|
3
3
|
* Provides helper functions for working with ComponentNode types
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ComponentNode,
|
|
8
|
+
ComponentInstanceNode,
|
|
9
|
+
HtmlNode,
|
|
10
|
+
SlotMarker,
|
|
11
|
+
EmbedNode,
|
|
12
|
+
LinkNode,
|
|
13
|
+
LocaleListNode,
|
|
14
|
+
ComponentDefinition,
|
|
15
|
+
StructuredComponentDefinition,
|
|
16
|
+
} from './types';
|
|
7
17
|
import type { ListNode } from './registry/nodeTypes/ListNodeType';
|
|
8
18
|
|
|
9
19
|
// For backward compatibility during migration
|
|
@@ -15,8 +25,20 @@ import { NODE_TYPE } from './constants';
|
|
|
15
25
|
* These are self-closing tags like <img />, <br />, <input />, etc.
|
|
16
26
|
*/
|
|
17
27
|
export const VOID_ELEMENTS = new Set([
|
|
18
|
-
'area',
|
|
19
|
-
'
|
|
28
|
+
'area',
|
|
29
|
+
'base',
|
|
30
|
+
'br',
|
|
31
|
+
'col',
|
|
32
|
+
'embed',
|
|
33
|
+
'hr',
|
|
34
|
+
'img',
|
|
35
|
+
'input',
|
|
36
|
+
'link',
|
|
37
|
+
'meta',
|
|
38
|
+
'param',
|
|
39
|
+
'source',
|
|
40
|
+
'track',
|
|
41
|
+
'wbr',
|
|
20
42
|
]);
|
|
21
43
|
|
|
22
44
|
/**
|
|
@@ -112,13 +134,13 @@ export function extractNodeProperties(node: ComponentNode): {
|
|
|
112
134
|
if (isComponentNode(node)) {
|
|
113
135
|
return {
|
|
114
136
|
componentName: node.component,
|
|
115
|
-
props: node.props || {}
|
|
137
|
+
props: node.props || {},
|
|
116
138
|
};
|
|
117
139
|
}
|
|
118
140
|
if (isHtmlNode(node)) {
|
|
119
141
|
return {
|
|
120
142
|
tag: node.tag,
|
|
121
|
-
props: {}
|
|
143
|
+
props: {},
|
|
122
144
|
};
|
|
123
145
|
}
|
|
124
146
|
return { props: {} };
|
|
@@ -129,7 +151,7 @@ export function extractNodeProperties(node: ComponentNode): {
|
|
|
129
151
|
* This is a heuristic based on naming conventions:
|
|
130
152
|
* - Components typically start with uppercase (e.g., "Card", "Button")
|
|
131
153
|
* - HTML elements are lowercase (e.g., "div", "span")
|
|
132
|
-
*
|
|
154
|
+
*
|
|
133
155
|
* Note: This is not foolproof, but works for most cases.
|
|
134
156
|
* For accurate detection, use component registry lookup.
|
|
135
157
|
*/
|
|
@@ -220,10 +242,17 @@ export function isListNode(node: unknown): node is ListNode {
|
|
|
220
242
|
/**
|
|
221
243
|
* Validate that a node type is valid
|
|
222
244
|
*/
|
|
223
|
-
export function isValidNodeType(type: string): type is typeof NODE_TYPE[keyof typeof NODE_TYPE] {
|
|
224
|
-
return
|
|
225
|
-
type === NODE_TYPE.
|
|
226
|
-
type === NODE_TYPE.
|
|
245
|
+
export function isValidNodeType(type: string): type is (typeof NODE_TYPE)[keyof typeof NODE_TYPE] {
|
|
246
|
+
return (
|
|
247
|
+
type === NODE_TYPE.NODE ||
|
|
248
|
+
type === NODE_TYPE.COMPONENT ||
|
|
249
|
+
type === NODE_TYPE.SLOT ||
|
|
250
|
+
type === NODE_TYPE.EMBED ||
|
|
251
|
+
type === NODE_TYPE.LINK ||
|
|
252
|
+
type === NODE_TYPE.LOCALE_LIST ||
|
|
253
|
+
type === NODE_TYPE.LIST ||
|
|
254
|
+
type === 'cms-list'
|
|
255
|
+
); // 'cms-list' supported for migration
|
|
227
256
|
}
|
|
228
257
|
|
|
229
258
|
/**
|
|
@@ -258,7 +287,12 @@ export function hasIf(node: ComponentNode): node is ComponentNode & { if: IfCond
|
|
|
258
287
|
* Check if a node is marked as slot content
|
|
259
288
|
*/
|
|
260
289
|
export function isSlotContent(node: unknown): boolean {
|
|
261
|
-
return
|
|
290
|
+
return (
|
|
291
|
+
node != null &&
|
|
292
|
+
typeof node === 'object' &&
|
|
293
|
+
'_isSlotContent' in node &&
|
|
294
|
+
(node as Record<string, unknown>)._isSlotContent === true
|
|
295
|
+
);
|
|
262
296
|
}
|
|
263
297
|
|
|
264
298
|
/**
|
|
@@ -389,10 +423,7 @@ export function isBooleanMapping(value: unknown): value is BooleanMapping {
|
|
|
389
423
|
* { visible: 'true' }
|
|
390
424
|
* ) // true
|
|
391
425
|
*/
|
|
392
|
-
export function evaluateNodeIf(
|
|
393
|
-
node: ComponentNode,
|
|
394
|
-
props?: Record<string, unknown>
|
|
395
|
-
): boolean {
|
|
426
|
+
export function evaluateNodeIf(node: ComponentNode, props?: Record<string, unknown>): boolean {
|
|
396
427
|
const ifValue = hasIf(node) ? node.if : undefined;
|
|
397
428
|
|
|
398
429
|
// No if property = render (default true)
|
|
@@ -441,7 +472,7 @@ export function evaluateNodeIf(
|
|
|
441
472
|
* @returns The same node with _isSlotContent: true added to all object nodes
|
|
442
473
|
*/
|
|
443
474
|
export function markAsSlotContent<T extends ComponentNode | ComponentNode[] | string | number | null | undefined>(
|
|
444
|
-
node: T
|
|
475
|
+
node: T,
|
|
445
476
|
): T {
|
|
446
477
|
if (!node || typeof node !== 'object') return node;
|
|
447
478
|
|
|
@@ -455,8 +486,8 @@ export function markAsSlotContent<T extends ComponentNode | ComponentNode[] | st
|
|
|
455
486
|
// Recursively mark children
|
|
456
487
|
if ('children' in node && node.children) {
|
|
457
488
|
if (Array.isArray(node.children)) {
|
|
458
|
-
node.children = node.children.map(child =>
|
|
459
|
-
typeof child === 'object' && child !== null ? markAsSlotContent(child) : child
|
|
489
|
+
node.children = node.children.map((child) =>
|
|
490
|
+
typeof child === 'object' && child !== null ? markAsSlotContent(child) : child,
|
|
460
491
|
) as typeof node.children;
|
|
461
492
|
} else if (typeof node.children === 'object') {
|
|
462
493
|
markAsSlotContent(node.children as ComponentNode);
|
|
@@ -465,4 +496,3 @@ export function markAsSlotContent<T extends ComponentNode | ComponentNode[] | st
|
|
|
465
496
|
|
|
466
497
|
return node;
|
|
467
498
|
}
|
|
468
|
-
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Array-based path utilities
|
|
3
3
|
* Paths are represented as number arrays internally: [0,0,1] instead of "root_0_children_0_children_1"
|
|
4
4
|
* Root is represented as [0] (or empty array [] depending on context)
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* This file maintains backward compatibility while using the new modular path system.
|
|
7
7
|
* All path utilities are re-exported from the organized path modules.
|
|
8
8
|
*/
|
|
@@ -11,7 +11,7 @@ import { resolve, sep } from 'path';
|
|
|
11
11
|
export class PathTraversalError extends Error {
|
|
12
12
|
constructor(
|
|
13
13
|
public readonly requestedPath: string,
|
|
14
|
-
public readonly rootPath: string
|
|
14
|
+
public readonly rootPath: string,
|
|
15
15
|
) {
|
|
16
16
|
super(`Path traversal detected: "${requestedPath}" escapes root "${rootPath}"`);
|
|
17
17
|
this.name = 'PathTraversalError';
|
|
@@ -94,7 +94,9 @@ describe('pathUtils', () => {
|
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
test('should handle deeply nested paths', () => {
|
|
97
|
-
expect(domPathToTreePath('root_children_0_children_1_children_2')).toBe(
|
|
97
|
+
expect(domPathToTreePath('root_children_0_children_1_children_2')).toBe(
|
|
98
|
+
'root_0_children_0_children_1_children_2',
|
|
99
|
+
);
|
|
98
100
|
});
|
|
99
101
|
});
|
|
100
102
|
|
|
@@ -115,11 +117,7 @@ describe('pathUtils', () => {
|
|
|
115
117
|
});
|
|
116
118
|
|
|
117
119
|
test('should handle deeply nested paths', () => {
|
|
118
|
-
expect(buildParentPaths([0, 0, 1, 2])).toEqual([
|
|
119
|
-
'root_0',
|
|
120
|
-
'root_0_children_0',
|
|
121
|
-
'root_0_children_0_children_1',
|
|
122
|
-
]);
|
|
120
|
+
expect(buildParentPaths([0, 0, 1, 2])).toEqual(['root_0', 'root_0_children_0', 'root_0_children_0_children_1']);
|
|
123
121
|
});
|
|
124
122
|
});
|
|
125
123
|
|
package/lib/shared/pathUtils.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { Path } from './paths';
|
|
7
|
-
import {
|
|
8
|
-
stringToPath,
|
|
9
|
-
pathToLegacyString,
|
|
7
|
+
import {
|
|
8
|
+
stringToPath,
|
|
9
|
+
pathToLegacyString,
|
|
10
10
|
getParentPath as getParentPathArray,
|
|
11
11
|
buildParentPaths as buildParentPathsArray,
|
|
12
12
|
pathsEqual,
|
|
@@ -14,59 +14,59 @@ import {
|
|
|
14
14
|
ROOT_STRING,
|
|
15
15
|
domPathStringToTreePath,
|
|
16
16
|
treePathToDomPathString,
|
|
17
|
-
isAncestorPath
|
|
17
|
+
isAncestorPath,
|
|
18
18
|
} from './paths';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Convert a page path to static HTML file path
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
23
|
* @example
|
|
24
24
|
* getStaticFilePath("/") -> "./dist/index.html"
|
|
25
25
|
* getStaticFilePath("/about") -> "./dist/about.html"
|
|
26
26
|
* getStaticFilePath("/blog/post-1") -> "./dist/blog-post-1.html"
|
|
27
27
|
*/
|
|
28
|
-
export function getStaticFilePath(pagePath: string, distDir: string =
|
|
29
|
-
if (pagePath ===
|
|
28
|
+
export function getStaticFilePath(pagePath: string, distDir: string = './dist'): string {
|
|
29
|
+
if (pagePath === '/') {
|
|
30
30
|
return `${distDir}/index.html`;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
// Convert /about -> about.html
|
|
34
34
|
// Convert /blog/post-1 -> blog-post-1.html (flat structure)
|
|
35
|
-
const pathParts = pagePath.substring(1).split(
|
|
36
|
-
const fileName = pathParts.join(
|
|
37
|
-
|
|
35
|
+
const pathParts = pagePath.substring(1).split('/');
|
|
36
|
+
const fileName = pathParts.join('-') + '.html';
|
|
37
|
+
|
|
38
38
|
return `${distDir}/${fileName}`;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Convert a page path to a page name (for file system)
|
|
43
|
-
*
|
|
43
|
+
*
|
|
44
44
|
* @example
|
|
45
45
|
* pathToPageName("/") -> "index"
|
|
46
46
|
* pathToPageName("/about") -> "about"
|
|
47
47
|
*/
|
|
48
48
|
export function pathToPageName(pagePath: string): string {
|
|
49
|
-
return pagePath ===
|
|
49
|
+
return pagePath === '/' ? 'index' : pagePath.substring(1);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Convert a page name to a page path
|
|
54
|
-
*
|
|
54
|
+
*
|
|
55
55
|
* @example
|
|
56
56
|
* pageNameToPath("index") -> "/"
|
|
57
57
|
* pageNameToPath("about") -> "/about"
|
|
58
58
|
*/
|
|
59
59
|
export function pageNameToPath(pageName: string): string {
|
|
60
|
-
return pageName ===
|
|
60
|
+
return pageName === 'index' ? '/' : `/${pageName}`;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Convert tree path to DOM path
|
|
65
65
|
* The tree adds a synthetic "root" container, so "root_0" in the tree corresponds to "root" in the DOM
|
|
66
66
|
* Also accepts array paths: [0] -> "root", [0,0] -> "root_children_0"
|
|
67
|
-
*
|
|
67
|
+
*
|
|
68
68
|
* Uses array operations internally for conversion.
|
|
69
|
-
*
|
|
69
|
+
*
|
|
70
70
|
* @example
|
|
71
71
|
* treePathToDomPath("root_0") -> "root"
|
|
72
72
|
* treePathToDomPath("root_0_children_0") -> "root_children_0"
|
|
@@ -83,9 +83,9 @@ export function treePathToDomPath(treePath: Path | string): string {
|
|
|
83
83
|
* Convert DOM path back to tree path
|
|
84
84
|
* The tree adds a synthetic "root" container, so "root" in the DOM corresponds to "root_0" in the tree
|
|
85
85
|
* Returns legacy string format for backward compatibility
|
|
86
|
-
*
|
|
86
|
+
*
|
|
87
87
|
* Uses array operations internally for conversion.
|
|
88
|
-
*
|
|
88
|
+
*
|
|
89
89
|
* @example
|
|
90
90
|
* domPathToTreePath("root") -> "root_0"
|
|
91
91
|
* domPathToTreePath("root_children_0") -> "root_0_children_0"
|
|
@@ -100,18 +100,18 @@ export function domPathToTreePath(domPath: string): string {
|
|
|
100
100
|
* Build parent paths for expanding tree nodes
|
|
101
101
|
* Returns all parent path segments for a given tree path
|
|
102
102
|
* Also accepts array paths
|
|
103
|
-
*
|
|
103
|
+
*
|
|
104
104
|
* @example
|
|
105
105
|
* buildParentPaths("root_0_children_0_children_1") -> ["root_0", "root_0_children_0"]
|
|
106
106
|
* buildParentPaths([0,0,1]) -> ["root_0", "root_0_children_0"]
|
|
107
107
|
*/
|
|
108
108
|
export function buildParentPaths(treePath: Path | string): string[] {
|
|
109
109
|
const pathArray = typeof treePath === 'string' ? stringToPath(treePath) : treePath;
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
if (isRootPathArray(pathArray)) {
|
|
112
112
|
return [];
|
|
113
113
|
}
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
const parentArrays = buildParentPathsArray(pathArray);
|
|
116
116
|
return parentArrays.map(pathToLegacyString);
|
|
117
117
|
}
|
|
@@ -134,43 +134,40 @@ export function getParentPathFromChildPath(childPath: Path | string): string {
|
|
|
134
134
|
* Convert component instance path to component structure path
|
|
135
135
|
* When editing a component, elements clicked inside the component instance on the page
|
|
136
136
|
* need to be converted to their paths within the component structure.
|
|
137
|
-
*
|
|
137
|
+
*
|
|
138
138
|
* Uses array operations internally for path manipulation.
|
|
139
|
-
*
|
|
139
|
+
*
|
|
140
140
|
* @example
|
|
141
141
|
* componentInstancePath: "root_children_0" (component instance on page)
|
|
142
142
|
* instancePath: "root_children_0_children_1" (element inside instance)
|
|
143
143
|
* Returns: "root_children_1" (component structure path)
|
|
144
|
-
*
|
|
144
|
+
*
|
|
145
145
|
* @param instancePath - Path of element within component instance on page (DOM path string)
|
|
146
146
|
* @param componentInstancePath - Path of the component instance root on the page (DOM path string)
|
|
147
147
|
* @returns Component structure path (always starts with "root")
|
|
148
148
|
*/
|
|
149
|
-
export function componentInstancePathToStructurePath(
|
|
150
|
-
instancePath: string,
|
|
151
|
-
componentInstancePath: string
|
|
152
|
-
): string {
|
|
149
|
+
export function componentInstancePathToStructurePath(instancePath: string, componentInstancePath: string): string {
|
|
153
150
|
// Convert DOM paths to arrays for manipulation
|
|
154
151
|
const instancePathArray = domPathStringToTreePath(instancePath);
|
|
155
152
|
const componentInstancePathArray = domPathStringToTreePath(componentInstancePath);
|
|
156
|
-
|
|
153
|
+
|
|
157
154
|
// Check if instancePath is inside componentInstancePath using array operations
|
|
158
155
|
if (!isAncestorPath(componentInstancePathArray, instancePathArray)) {
|
|
159
156
|
// Not inside component instance - return as-is (shouldn't happen, but handle gracefully)
|
|
160
157
|
return instancePath;
|
|
161
158
|
}
|
|
162
|
-
|
|
159
|
+
|
|
163
160
|
// Extract relative path using array operations
|
|
164
161
|
// componentInstancePathArray: [0, 0] -> instancePathArray: [0, 0, 1]
|
|
165
162
|
// relative: [1] -> convert to DOM path: "root_children_1"
|
|
166
163
|
const relativePathArray = instancePathArray.slice(componentInstancePathArray.length);
|
|
167
|
-
|
|
164
|
+
|
|
168
165
|
// Convert relative path array back to DOM path string
|
|
169
166
|
// If relative is empty, return root
|
|
170
167
|
if (relativePathArray.length === 0) {
|
|
171
168
|
return ROOT_STRING;
|
|
172
169
|
}
|
|
173
|
-
|
|
170
|
+
|
|
174
171
|
// Build component structure path: root + relative path
|
|
175
172
|
return treePathToDomPathString(relativePathArray);
|
|
176
173
|
}
|
|
@@ -179,34 +176,31 @@ export function componentInstancePathToStructurePath(
|
|
|
179
176
|
* Convert component structure path to component instance path
|
|
180
177
|
* When selecting an element in the component structure tree, convert it to
|
|
181
178
|
* the path within the component instance on the page.
|
|
182
|
-
*
|
|
179
|
+
*
|
|
183
180
|
* Uses array operations internally for path manipulation.
|
|
184
|
-
*
|
|
181
|
+
*
|
|
185
182
|
* @example
|
|
186
183
|
* componentInstancePath: "root_children_0" (component instance on page)
|
|
187
184
|
* structurePath: "root_children_1" (element in component structure)
|
|
188
185
|
* Returns: "root_children_0_children_1" (path within instance on page)
|
|
189
|
-
*
|
|
186
|
+
*
|
|
190
187
|
* @param structurePath - Path within component structure (starts with "root", DOM path string)
|
|
191
188
|
* @param componentInstancePath - Path of the component instance root on the page (DOM path string)
|
|
192
189
|
* @returns Path within component instance on page (DOM path string)
|
|
193
190
|
*/
|
|
194
|
-
export function componentStructurePathToInstancePath(
|
|
195
|
-
structurePath: string,
|
|
196
|
-
componentInstancePath: string
|
|
197
|
-
): string {
|
|
191
|
+
export function componentStructurePathToInstancePath(structurePath: string, componentInstancePath: string): string {
|
|
198
192
|
// Convert DOM paths to arrays for manipulation
|
|
199
193
|
const structurePathArray = domPathStringToTreePath(structurePath);
|
|
200
194
|
const componentInstancePathArray = domPathStringToTreePath(componentInstancePath);
|
|
201
|
-
|
|
195
|
+
|
|
202
196
|
// Extract relative path from structure path (skip root [0])
|
|
203
197
|
// structurePathArray: [0, 1] -> relative: [1]
|
|
204
198
|
const relativePathArray = structurePathArray.slice(1);
|
|
205
|
-
|
|
199
|
+
|
|
206
200
|
// Combine component instance path with relative path using array operations
|
|
207
201
|
// componentInstancePathArray: [0, 0] + relativePathArray: [1] -> [0, 0, 1]
|
|
208
202
|
const instancePathArray: Path = [...componentInstancePathArray, ...relativePathArray];
|
|
209
|
-
|
|
203
|
+
|
|
210
204
|
// Convert back to DOM path string
|
|
211
205
|
return treePathToDomPathString(instancePathArray);
|
|
212
206
|
}
|
|
@@ -214,9 +208,9 @@ export function componentStructurePathToInstancePath(
|
|
|
214
208
|
/**
|
|
215
209
|
* Convert path for component editing context
|
|
216
210
|
* When editing a component, converts component instance paths to component structure paths
|
|
217
|
-
*
|
|
211
|
+
*
|
|
218
212
|
* Uses array operations internally for path manipulation.
|
|
219
|
-
*
|
|
213
|
+
*
|
|
220
214
|
* @param path - Path array from canvas
|
|
221
215
|
* @param isEditingComponent - Whether we're editing a component
|
|
222
216
|
* @param componentInstancePath - Path of component instance on page (if editing component, Path array)
|
|
@@ -225,7 +219,7 @@ export function componentStructurePathToInstancePath(
|
|
|
225
219
|
export function convertPathForComponentContext(
|
|
226
220
|
path: Path,
|
|
227
221
|
isEditingComponent: boolean,
|
|
228
|
-
componentInstancePath: Path | null
|
|
222
|
+
componentInstancePath: Path | null,
|
|
229
223
|
): Path {
|
|
230
224
|
if (isEditingComponent && componentInstancePath) {
|
|
231
225
|
// Check if path is inside componentInstancePath using array operations
|
|
@@ -233,12 +227,12 @@ export function convertPathForComponentContext(
|
|
|
233
227
|
// Extract relative path: componentInstancePath: [0, 0] -> path: [0, 0, 1]
|
|
234
228
|
// relative: [1] -> component structure path: [0, 1]
|
|
235
229
|
const relativePath = path.slice(componentInstancePath.length);
|
|
236
|
-
|
|
230
|
+
|
|
237
231
|
// Build component structure path: [0] + relative path
|
|
238
232
|
return [0, ...relativePath];
|
|
239
233
|
}
|
|
240
234
|
}
|
|
241
|
-
|
|
235
|
+
|
|
242
236
|
// Regular page editing - return path as-is
|
|
243
237
|
return path;
|
|
244
238
|
}
|