mordoc 0.1.13 → 1.0.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/LICENSE +7 -0
- package/bin/cli.js +24 -71
- package/dist/cli/asset-rewrite.d.ts +40 -0
- package/dist/cli/asset-rewrite.d.ts.map +1 -0
- package/dist/cli/asset-rewrite.js +67 -0
- package/dist/cli/asset-rewrite.js.map +1 -0
- package/dist/cli/build.d.ts +45 -15
- package/dist/cli/build.d.ts.map +1 -1
- package/dist/cli/build.js +186 -101
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts +26 -14
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dev.js +116 -159
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/pagefind-indexer.d.ts +15 -0
- package/dist/cli/pagefind-indexer.d.ts.map +1 -0
- package/dist/cli/pagefind-indexer.js +68 -0
- package/dist/cli/pagefind-indexer.js.map +1 -0
- package/dist/cli/paths.d.ts +26 -0
- package/dist/cli/paths.d.ts.map +1 -0
- package/dist/cli/paths.js +32 -0
- package/dist/cli/paths.js.map +1 -0
- package/dist/cli/ssg-runner.d.ts +58 -0
- package/dist/cli/ssg-runner.d.ts.map +1 -0
- package/dist/cli/ssg-runner.js +126 -0
- package/dist/cli/ssg-runner.js.map +1 -0
- package/dist/config/assets-loader.d.ts +11 -0
- package/dist/config/assets-loader.d.ts.map +1 -0
- package/dist/config/assets-loader.js +46 -0
- package/dist/config/assets-loader.js.map +1 -0
- package/dist/config/language-loader.d.ts +11 -0
- package/dist/config/language-loader.d.ts.map +1 -0
- package/dist/config/language-loader.js +61 -0
- package/dist/config/language-loader.js.map +1 -0
- package/dist/config/language.d.ts +11 -0
- package/dist/config/language.d.ts.map +1 -0
- package/dist/config/language.js +61 -0
- package/dist/config/language.js.map +1 -0
- package/dist/config/sidenav-loader.d.ts +14 -0
- package/dist/config/sidenav-loader.d.ts.map +1 -0
- package/dist/config/sidenav-loader.js +78 -0
- package/dist/config/sidenav-loader.js.map +1 -0
- package/dist/config/site-loader.d.ts +11 -0
- package/dist/config/site-loader.d.ts.map +1 -0
- package/dist/config/site-loader.js +72 -0
- package/dist/config/site-loader.js.map +1 -0
- package/dist/config/site.d.ts +11 -0
- package/dist/config/site.d.ts.map +1 -0
- package/dist/config/site.js +72 -0
- package/dist/config/site.js.map +1 -0
- package/dist/config/topnav-loader.d.ts +10 -0
- package/dist/config/topnav-loader.d.ts.map +1 -0
- package/dist/config/topnav-loader.js +78 -0
- package/dist/config/topnav-loader.js.map +1 -0
- package/dist/config/translations-loader.d.ts +7 -0
- package/dist/config/translations-loader.d.ts.map +1 -0
- package/dist/config/translations-loader.js +51 -0
- package/dist/config/translations-loader.js.map +1 -0
- package/dist/content/content-loader.d.ts +16 -0
- package/dist/content/content-loader.d.ts.map +1 -0
- package/dist/content/content-loader.js +126 -0
- package/dist/content/content-loader.js.map +1 -0
- package/dist/content/content-parser.d.ts +12 -0
- package/dist/content/content-parser.d.ts.map +1 -0
- package/dist/content/content-parser.js +54 -0
- package/dist/content/content-parser.js.map +1 -0
- package/dist/content/content-transformer.d.ts +17 -0
- package/dist/content/content-transformer.d.ts.map +1 -0
- package/dist/content/content-transformer.js +94 -0
- package/dist/content/content-transformer.js.map +1 -0
- package/dist/content/markdoc-config.d.ts +13 -0
- package/dist/content/markdoc-config.d.ts.map +1 -0
- package/dist/content/markdoc-config.js +210 -0
- package/dist/content/markdoc-config.js.map +1 -0
- package/dist/content/slug.d.ts +26 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +31 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/pipeline.d.ts +61 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +123 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/types/assets.d.ts +15 -0
- package/dist/types/assets.d.ts.map +1 -0
- package/dist/types/assets.js +2 -0
- package/dist/types/assets.js.map +1 -0
- package/dist/types/content.d.ts +114 -32
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/content.js +1 -6
- package/dist/types/content.js.map +1 -1
- package/dist/types/language.d.ts +9 -0
- package/dist/types/language.d.ts.map +1 -0
- package/dist/types/language.js +2 -0
- package/dist/types/language.js.map +1 -0
- package/dist/types/navigation.d.ts +24 -36
- package/dist/types/navigation.d.ts.map +1 -1
- package/dist/types/navigation.js +1 -6
- package/dist/types/navigation.js.map +1 -1
- package/dist/types/pipeline.d.ts +70 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +2 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/types/site.d.ts +20 -0
- package/dist/types/site.d.ts.map +1 -0
- package/dist/types/site.js +2 -0
- package/dist/types/site.js.map +1 -0
- package/dist/utils/lang-utils.d.ts +23 -0
- package/dist/utils/lang-utils.d.ts.map +1 -0
- package/dist/utils/lang-utils.js +40 -0
- package/dist/utils/lang-utils.js.map +1 -0
- package/dist/utils/paths.d.ts +25 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +31 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/vite/plugin.d.ts +93 -0
- package/dist/vite/plugin.d.ts.map +1 -0
- package/dist/vite/plugin.js +435 -0
- package/dist/vite/plugin.js.map +1 -0
- package/package.json +46 -61
- package/src/app/App.module.css +82 -0
- package/src/app/App.tsx +95 -0
- package/src/app/content/Content.module.css +357 -0
- package/src/app/content/Content.tsx +212 -0
- package/src/app/content/callout/Callout.module.css +110 -0
- package/src/app/content/callout/Callout.tsx +82 -0
- package/src/app/content/card/Card.module.css +146 -0
- package/src/app/content/card/Card.tsx +110 -0
- package/src/app/content/card/CardGrid.module.css +22 -0
- package/src/app/content/card/CardGrid.tsx +34 -0
- package/src/app/content/code-block/CodeBlock.module.css +237 -0
- package/src/app/content/code-block/CodeBlock.tsx +123 -0
- package/src/app/content/heading/Heading.module.css +52 -0
- package/src/app/content/heading/Heading.tsx +75 -0
- package/src/app/content/image/Image.module.css +113 -0
- package/src/app/content/image/Image.tsx +98 -0
- package/src/app/content/link/ContentLink.tsx +46 -0
- package/src/app/data-context.tsx +39 -0
- package/src/app/entry-server.tsx +58 -0
- package/src/app/footer/Footer.module.css +36 -0
- package/src/app/footer/Footer.tsx +28 -0
- package/src/app/globals.d.ts +40 -0
- package/src/app/header/Header.module.css +205 -0
- package/src/app/header/Header.tsx +188 -0
- package/src/app/header/LanguagePicker.module.css +97 -0
- package/src/app/header/LanguagePicker.tsx +174 -0
- package/src/app/header/SearchBar.module.css +92 -0
- package/src/app/header/SearchBar.tsx +37 -0
- package/src/app/header/SearchModal.module.css +185 -0
- package/src/app/header/SearchModal.tsx +245 -0
- package/src/app/header/Topnav.module.css +37 -0
- package/src/app/header/Topnav.tsx +30 -0
- package/src/app/index.css +119 -0
- package/src/app/index.html +13 -0
- package/src/app/landing/LandingPage.module.css +14 -0
- package/src/app/landing/LandingPage.tsx +62 -0
- package/src/app/landing/button/Button.module.css +37 -0
- package/src/app/landing/button/Button.tsx +50 -0
- package/src/app/landing/hero/Hero.module.css +108 -0
- package/src/app/landing/hero/Hero.tsx +81 -0
- package/src/app/landing/section/Section.module.css +100 -0
- package/src/app/landing/section/Section.tsx +61 -0
- package/src/app/lang-utils.ts +11 -0
- package/src/app/main.tsx +67 -0
- package/src/app/not-found/NotFound.module.css +92 -0
- package/src/app/not-found/NotFound.tsx +34 -0
- package/src/app/routes.tsx +86 -0
- package/src/app/sidenav/Sidenav.module.css +239 -0
- package/src/app/sidenav/Sidenav.tsx +182 -0
- package/src/app/skeleton/Skeleton.module.css +100 -0
- package/src/app/skeleton/Skeleton.tsx +75 -0
- package/src/app/toc/Toc.module.css +59 -0
- package/src/app/toc/Toc.tsx +77 -0
- package/src/app/tsconfig.json +18 -0
- package/src/app/virtual-modules.d.ts +74 -0
- package/dist/assets/fonts/inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/dist/assets/fonts/inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/dist/assets/fonts/inter/OFL.txt +0 -93
- package/dist/build/Builder.d.ts +0 -92
- package/dist/build/Builder.d.ts.map +0 -1
- package/dist/build/Builder.js +0 -394
- package/dist/build/Builder.js.map +0 -1
- package/dist/build/ClientBundler.d.ts +0 -48
- package/dist/build/ClientBundler.d.ts.map +0 -1
- package/dist/build/ClientBundler.js +0 -169
- package/dist/build/ClientBundler.js.map +0 -1
- package/dist/build/HtmlGenerator.d.ts +0 -46
- package/dist/build/HtmlGenerator.d.ts.map +0 -1
- package/dist/build/HtmlGenerator.js +0 -190
- package/dist/build/HtmlGenerator.js.map +0 -1
- package/dist/build/SearchIndexer.d.ts +0 -31
- package/dist/build/SearchIndexer.d.ts.map +0 -1
- package/dist/build/SearchIndexer.js +0 -116
- package/dist/build/SearchIndexer.js.map +0 -1
- package/dist/bundles/client.js +0 -126
- package/dist/cli/create-app.d.ts +0 -14
- package/dist/cli/create-app.d.ts.map +0 -1
- package/dist/cli/create-app.js +0 -241
- package/dist/cli/create-app.js.map +0 -1
- package/dist/client/App.d.ts +0 -17
- package/dist/client/App.d.ts.map +0 -1
- package/dist/client/App.js +0 -91
- package/dist/client/App.js.map +0 -1
- package/dist/client/contexts/ConfigContext.d.ts +0 -22
- package/dist/client/contexts/ConfigContext.d.ts.map +0 -1
- package/dist/client/contexts/ConfigContext.js +0 -27
- package/dist/client/contexts/ConfigContext.js.map +0 -1
- package/dist/client/contexts/ContentContext.d.ts +0 -31
- package/dist/client/contexts/ContentContext.d.ts.map +0 -1
- package/dist/client/contexts/ContentContext.js +0 -46
- package/dist/client/contexts/ContentContext.js.map +0 -1
- package/dist/client/contexts/SearchContext.d.ts +0 -38
- package/dist/client/contexts/SearchContext.d.ts.map +0 -1
- package/dist/client/contexts/SearchContext.js +0 -185
- package/dist/client/contexts/SearchContext.js.map +0 -1
- package/dist/client/contexts/ThemeContext.d.ts +0 -23
- package/dist/client/contexts/ThemeContext.d.ts.map +0 -1
- package/dist/client/contexts/ThemeContext.js +0 -53
- package/dist/client/contexts/ThemeContext.js.map +0 -1
- package/dist/client/hooks/useContent.d.ts +0 -12
- package/dist/client/hooks/useContent.d.ts.map +0 -1
- package/dist/client/hooks/useContent.js +0 -74
- package/dist/client/hooks/useContent.js.map +0 -1
- package/dist/client/hooks/useNavigation.d.ts +0 -15
- package/dist/client/hooks/useNavigation.d.ts.map +0 -1
- package/dist/client/hooks/useNavigation.js +0 -101
- package/dist/client/hooks/useNavigation.js.map +0 -1
- package/dist/client/hooks/useSearch.d.ts +0 -22
- package/dist/client/hooks/useSearch.d.ts.map +0 -1
- package/dist/client/hooks/useSearch.js +0 -64
- package/dist/client/hooks/useSearch.js.map +0 -1
- package/dist/client/main.d.ts +0 -5
- package/dist/client/main.d.ts.map +0 -1
- package/dist/client/main.js +0 -66
- package/dist/client/main.js.map +0 -1
- package/dist/components/Callout.d.ts +0 -9
- package/dist/components/Callout.d.ts.map +0 -1
- package/dist/components/Callout.js +0 -24
- package/dist/components/Callout.js.map +0 -1
- package/dist/components/Card.d.ts +0 -10
- package/dist/components/Card.d.ts.map +0 -1
- package/dist/components/Card.js +0 -15
- package/dist/components/Card.js.map +0 -1
- package/dist/components/CardGrid.d.ts +0 -8
- package/dist/components/CardGrid.d.ts.map +0 -1
- package/dist/components/CardGrid.js +0 -9
- package/dist/components/CardGrid.js.map +0 -1
- package/dist/components/CodeBlock.d.ts +0 -28
- package/dist/components/CodeBlock.d.ts.map +0 -1
- package/dist/components/CodeBlock.js +0 -80
- package/dist/components/CodeBlock.js.map +0 -1
- package/dist/components/ContentPage.d.ts +0 -9
- package/dist/components/ContentPage.d.ts.map +0 -1
- package/dist/components/ContentPage.js +0 -102
- package/dist/components/ContentPage.js.map +0 -1
- package/dist/components/Header.d.ts +0 -14
- package/dist/components/Header.d.ts.map +0 -1
- package/dist/components/Header.js +0 -30
- package/dist/components/Header.js.map +0 -1
- package/dist/components/Heading.d.ts +0 -16
- package/dist/components/Heading.d.ts.map +0 -1
- package/dist/components/Heading.js +0 -31
- package/dist/components/Heading.js.map +0 -1
- package/dist/components/Image.d.ts +0 -8
- package/dist/components/Image.d.ts.map +0 -1
- package/dist/components/Image.js +0 -24
- package/dist/components/Image.js.map +0 -1
- package/dist/components/Layout.d.ts +0 -14
- package/dist/components/Layout.d.ts.map +0 -1
- package/dist/components/Layout.js +0 -32
- package/dist/components/Layout.js.map +0 -1
- package/dist/components/MarkdocRenderer.d.ts +0 -15
- package/dist/components/MarkdocRenderer.d.ts.map +0 -1
- package/dist/components/MarkdocRenderer.js +0 -73
- package/dist/components/MarkdocRenderer.js.map +0 -1
- package/dist/components/MobileMenu.d.ts +0 -14
- package/dist/components/MobileMenu.d.ts.map +0 -1
- package/dist/components/MobileMenu.js +0 -45
- package/dist/components/MobileMenu.js.map +0 -1
- package/dist/components/PageNavigation.d.ts +0 -9
- package/dist/components/PageNavigation.d.ts.map +0 -1
- package/dist/components/PageNavigation.js +0 -23
- package/dist/components/PageNavigation.js.map +0 -1
- package/dist/components/SearchModal.d.ts +0 -9
- package/dist/components/SearchModal.d.ts.map +0 -1
- package/dist/components/SearchModal.js +0 -74
- package/dist/components/SearchModal.js.map +0 -1
- package/dist/components/SideNav.d.ts +0 -9
- package/dist/components/SideNav.d.ts.map +0 -1
- package/dist/components/SideNav.js +0 -66
- package/dist/components/SideNav.js.map +0 -1
- package/dist/components/TableOfContents.d.ts +0 -10
- package/dist/components/TableOfContents.d.ts.map +0 -1
- package/dist/components/TableOfContents.js +0 -151
- package/dist/components/TableOfContents.js.map +0 -1
- package/dist/config/ConfigLoader.d.ts +0 -50
- package/dist/config/ConfigLoader.d.ts.map +0 -1
- package/dist/config/ConfigLoader.js +0 -214
- package/dist/config/ConfigLoader.js.map +0 -1
- package/dist/config/StyleCompiler.d.ts +0 -17
- package/dist/config/StyleCompiler.d.ts.map +0 -1
- package/dist/config/StyleCompiler.js +0 -116
- package/dist/config/StyleCompiler.js.map +0 -1
- package/dist/config/ThemeGenerator.d.ts +0 -14
- package/dist/config/ThemeGenerator.d.ts.map +0 -1
- package/dist/config/ThemeGenerator.js +0 -129
- package/dist/config/ThemeGenerator.js.map +0 -1
- package/dist/content/ContentLoader.d.ts +0 -70
- package/dist/content/ContentLoader.d.ts.map +0 -1
- package/dist/content/ContentLoader.js +0 -146
- package/dist/content/ContentLoader.js.map +0 -1
- package/dist/content/ContentProcessor.d.ts +0 -84
- package/dist/content/ContentProcessor.d.ts.map +0 -1
- package/dist/content/ContentProcessor.js +0 -380
- package/dist/content/ContentProcessor.js.map +0 -1
- package/dist/content/RouteManager.d.ts +0 -69
- package/dist/content/RouteManager.d.ts.map +0 -1
- package/dist/content/RouteManager.js +0 -143
- package/dist/content/RouteManager.js.map +0 -1
- package/dist/styles/components/callout.d.ts +0 -11
- package/dist/styles/components/callout.d.ts.map +0 -1
- package/dist/styles/components/callout.js +0 -87
- package/dist/styles/components/callout.js.map +0 -1
- package/dist/styles/components/card.d.ts +0 -11
- package/dist/styles/components/card.d.ts.map +0 -1
- package/dist/styles/components/card.js +0 -179
- package/dist/styles/components/card.js.map +0 -1
- package/dist/styles/components/codeblock.d.ts +0 -11
- package/dist/styles/components/codeblock.d.ts.map +0 -1
- package/dist/styles/components/codeblock.js +0 -251
- package/dist/styles/components/codeblock.js.map +0 -1
- package/dist/styles/components/content.d.ts +0 -11
- package/dist/styles/components/content.d.ts.map +0 -1
- package/dist/styles/components/content.js +0 -197
- package/dist/styles/components/content.js.map +0 -1
- package/dist/styles/components/fonts.d.ts +0 -11
- package/dist/styles/components/fonts.d.ts.map +0 -1
- package/dist/styles/components/fonts.js +0 -34
- package/dist/styles/components/fonts.js.map +0 -1
- package/dist/styles/components/header.d.ts +0 -11
- package/dist/styles/components/header.d.ts.map +0 -1
- package/dist/styles/components/header.js +0 -293
- package/dist/styles/components/header.js.map +0 -1
- package/dist/styles/components/heading.d.ts +0 -11
- package/dist/styles/components/heading.d.ts.map +0 -1
- package/dist/styles/components/heading.js +0 -115
- package/dist/styles/components/heading.js.map +0 -1
- package/dist/styles/components/layout.d.ts +0 -11
- package/dist/styles/components/layout.d.ts.map +0 -1
- package/dist/styles/components/layout.js +0 -79
- package/dist/styles/components/layout.js.map +0 -1
- package/dist/styles/components/mobilemenu.d.ts +0 -11
- package/dist/styles/components/mobilemenu.d.ts.map +0 -1
- package/dist/styles/components/mobilemenu.js +0 -112
- package/dist/styles/components/mobilemenu.js.map +0 -1
- package/dist/styles/components/reset.d.ts +0 -11
- package/dist/styles/components/reset.d.ts.map +0 -1
- package/dist/styles/components/reset.js +0 -131
- package/dist/styles/components/reset.js.map +0 -1
- package/dist/styles/components/searchmodal.d.ts +0 -11
- package/dist/styles/components/searchmodal.d.ts.map +0 -1
- package/dist/styles/components/searchmodal.js +0 -333
- package/dist/styles/components/searchmodal.js.map +0 -1
- package/dist/styles/components/sidenav.d.ts +0 -11
- package/dist/styles/components/sidenav.d.ts.map +0 -1
- package/dist/styles/components/sidenav.js +0 -212
- package/dist/styles/components/sidenav.js.map +0 -1
- package/dist/styles/components/toc.d.ts +0 -11
- package/dist/styles/components/toc.d.ts.map +0 -1
- package/dist/styles/components/toc.js +0 -120
- package/dist/styles/components/toc.js.map +0 -1
- package/dist/styles/components/typography.d.ts +0 -11
- package/dist/styles/components/typography.d.ts.map +0 -1
- package/dist/styles/components/typography.js +0 -248
- package/dist/styles/components/typography.js.map +0 -1
- package/dist/styles/components/utility.d.ts +0 -11
- package/dist/styles/components/utility.d.ts.map +0 -1
- package/dist/styles/components/utility.js +0 -231
- package/dist/styles/components/utility.js.map +0 -1
- package/dist/styles/types.d.ts +0 -79
- package/dist/styles/types.d.ts.map +0 -1
- package/dist/styles/types.js +0 -7
- package/dist/styles/types.js.map +0 -1
- package/dist/styles/utils.d.ts +0 -21
- package/dist/styles/utils.d.ts.map +0 -1
- package/dist/styles/utils.js +0 -50
- package/dist/styles/utils.js.map +0 -1
- package/dist/styles/variables/main.d.ts +0 -15
- package/dist/styles/variables/main.d.ts.map +0 -1
- package/dist/styles/variables/main.js +0 -116
- package/dist/styles/variables/main.js.map +0 -1
- package/dist/types/config.d.ts +0 -43
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js +0 -7
- package/dist/types/config.js.map +0 -1
- package/dist/utils/language-utils.d.ts +0 -41
- package/dist/utils/language-utils.d.ts.map +0 -1
- package/dist/utils/language-utils.js +0 -79
- package/dist/utils/language-utils.js.map +0 -1
- package/dist/utils/slugify.d.ts +0 -20
- package/dist/utils/slugify.d.ts.map +0 -1
- package/dist/utils/slugify.js +0 -44
- package/dist/utils/slugify.js.map +0 -1
- package/templates/default/config/favicon.ico +0 -0
- package/templates/default/config/logo-dark.png +0 -0
- package/templates/default/config/logo.png +0 -0
- package/templates/default/config/sidenav.yaml +0 -36
- package/templates/default/config/site.json +0 -16
- package/templates/default/config/styles/main.json +0 -6
- package/templates/default/config/styles/typography.json +0 -6
- package/templates/default/content/en/changelog.md +0 -35
- package/templates/default/content/en/faq.md +0 -50
- package/templates/default/content/en/field-manual/engines.md +0 -59
- package/templates/default/content/en/field-manual/relativity.md +0 -46
- package/templates/default/content/en/field-manual/safety.md +0 -44
- package/templates/default/content/en/field-manual.md +0 -22
- package/templates/default/content/en/flight-school/navigation.md +0 -61
- package/templates/default/content/en/flight-school/primer.md +0 -64
- package/templates/default/content/en/flight-school.md +0 -48
- package/templates/default/content/en/index.md +0 -83
- package/templates/default/content/en/ship-systems/flux-sails.md +0 -33
- package/templates/default/content/en/ship-systems/photonic-core.md +0 -39
- package/templates/default/content/en/ship-systems.md +0 -25
- package/templates/default/package.json +0 -21
- package/templates/default/public/icons/academy.svg +0 -15
- package/templates/default/public/icons/manual.svg +0 -16
- package/templates/default/public/icons/relativity.svg +0 -16
- package/templates/default/public/icons/systems.svg +0 -14
- package/templates/default/public/icons/warning.svg +0 -14
- package/templates/default/public/images/flux-sails.svg +0 -33
- package/templates/default/public/images/photonic-core.svg +0 -44
- package/templates/default/public/images/starwake.svg +0 -49
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
// Relative path to the site config file within any Mordoc project root.
|
|
4
|
+
const SITE_CONFIG_PATH = join('config', 'site.json');
|
|
5
|
+
// Fields that must be present and non-empty for a config to be considered valid.
|
|
6
|
+
const REQUIRED_FIELDS = [
|
|
7
|
+
'name',
|
|
8
|
+
'description',
|
|
9
|
+
'baseUrl',
|
|
10
|
+
'defaultLanguage',
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Validates the raw parsed JSON from site.json and narrows it to SiteConfig.
|
|
14
|
+
* Throws a descriptive error if any required field is missing or malformed,
|
|
15
|
+
* so the user gets actionable feedback rather than a cryptic runtime crash.
|
|
16
|
+
*/
|
|
17
|
+
function validateSiteConfig(raw) {
|
|
18
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
19
|
+
throw new Error('site.json must contain a JSON object.');
|
|
20
|
+
}
|
|
21
|
+
const obj = raw;
|
|
22
|
+
for (const field of REQUIRED_FIELDS) {
|
|
23
|
+
if (typeof obj[field] !== 'string' || obj[field] === '') {
|
|
24
|
+
throw new Error(`site.json: "${field}" is required and must be a non-empty string.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Validate baseUrl with the built-in URL parser — it handles all the edge
|
|
28
|
+
// cases (missing protocol, invalid characters, etc.) so we don't have to.
|
|
29
|
+
const baseUrl = obj['baseUrl'];
|
|
30
|
+
try {
|
|
31
|
+
new URL(baseUrl);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new Error(`site.json: "baseUrl" must be a valid URL. Got: "${baseUrl}"`);
|
|
35
|
+
}
|
|
36
|
+
// A trailing slash on baseUrl would cause double-slashes when paths are appended.
|
|
37
|
+
if (baseUrl.endsWith('/')) {
|
|
38
|
+
throw new Error(`site.json: "baseUrl" must not end with a trailing slash. Got: "${baseUrl}"`);
|
|
39
|
+
}
|
|
40
|
+
return raw;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Reads and validates the site.json config file for a Mordoc project.
|
|
44
|
+
*
|
|
45
|
+
* @param projectRoot - Absolute path to the project's root directory.
|
|
46
|
+
* @returns The validated site configuration object.
|
|
47
|
+
* @throws If the file is missing, unreadable, contains invalid JSON,
|
|
48
|
+
* or fails field validation.
|
|
49
|
+
*/
|
|
50
|
+
export async function loadSiteConfig(projectRoot) {
|
|
51
|
+
const filePath = join(projectRoot, SITE_CONFIG_PATH);
|
|
52
|
+
let content;
|
|
53
|
+
try {
|
|
54
|
+
content = await readFile(filePath, 'utf-8');
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const code = err.code;
|
|
58
|
+
if (code === 'ENOENT') {
|
|
59
|
+
throw new Error(`Config file not found: ${filePath}\nEvery Mordoc project requires a config/site.json file.`);
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Failed to read ${filePath}: ${err.message}`);
|
|
62
|
+
}
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = JSON.parse(content);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new Error(`Failed to parse ${filePath}: Invalid JSON.`);
|
|
69
|
+
}
|
|
70
|
+
return validateSiteConfig(parsed);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=site.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../../src/config/site.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,wEAAwE;AACxE,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAErD,iFAAiF;AACjF,MAAM,eAAe,GAAyB;IAC5C,MAAM;IACN,aAAa;IACb,SAAS;IACT,iBAAiB;CAClB,CAAC;AAEF;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAY;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,+CAA+C,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAW,CAAC;IACzC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mDAAmD,OAAO,GAAG,CAAC,CAAC;IACjF,CAAC;IAED,kFAAkF;IAClF,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,kEAAkE,OAAO,GAAG,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,GAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAErD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,0DAA0D,CAAC,CAAC;QAChH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,iBAAiB,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ResolvedTopnavConfig } from '../types/navigation.js';
|
|
2
|
+
/**
|
|
3
|
+
* Loads config/navigation/topnav.yaml and resolves all referenced sidenav files.
|
|
4
|
+
* Returns null if topnav.yaml does not exist (single-sidenav project).
|
|
5
|
+
*
|
|
6
|
+
* @param projectRoot - Absolute path to the project's root directory.
|
|
7
|
+
* @returns The resolved topnav with loaded sidenavs, or null if topnav.yaml is absent.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadTopnavConfig(projectRoot: string): Promise<ResolvedTopnavConfig | null>;
|
|
10
|
+
//# sourceMappingURL=topnav-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topnav-loader.d.ts","sourceRoot":"","sources":["../../src/config/topnav-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA4B,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAiD7F;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAkChG"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
import { loadSidenavFile } from './sidenav-loader.js';
|
|
5
|
+
const NAV_DIR = join('config', 'navigation');
|
|
6
|
+
const TOPNAV_CONFIG_PATH = join(NAV_DIR, 'topnav.yaml');
|
|
7
|
+
function validateTopnavConfig(raw) {
|
|
8
|
+
if (!Array.isArray(raw)) {
|
|
9
|
+
throw new Error('topnav.yaml: file must contain a YAML array at the top level.');
|
|
10
|
+
}
|
|
11
|
+
if (raw.length === 0) {
|
|
12
|
+
throw new Error('topnav.yaml: navigation array must not be empty.');
|
|
13
|
+
}
|
|
14
|
+
const seenSidenavs = new Set();
|
|
15
|
+
for (const [index, entry] of raw.entries()) {
|
|
16
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
17
|
+
throw new Error(`topnav.yaml: items[${index}] must be an object.`);
|
|
18
|
+
}
|
|
19
|
+
const obj = entry;
|
|
20
|
+
if (typeof obj['label'] !== 'string' || obj['label'] === '') {
|
|
21
|
+
throw new Error(`topnav.yaml: items[${index}].label is required and must be a non-empty string.`);
|
|
22
|
+
}
|
|
23
|
+
if (typeof obj['path'] !== 'string' || obj['path'] === '') {
|
|
24
|
+
throw new Error(`topnav.yaml: items[${index}].path is required and must be a non-empty string.`);
|
|
25
|
+
}
|
|
26
|
+
if (typeof obj['sidenav'] !== 'string' || obj['sidenav'] === '') {
|
|
27
|
+
throw new Error(`topnav.yaml: items[${index}].sidenav is required and must be a non-empty string.`);
|
|
28
|
+
}
|
|
29
|
+
if (!obj['sidenav'].endsWith('.yaml') && !obj['sidenav'].endsWith('.yml')) {
|
|
30
|
+
throw new Error(`topnav.yaml: items[${index}].sidenav must be a .yaml or .yml filename.`);
|
|
31
|
+
}
|
|
32
|
+
if (seenSidenavs.has(obj['sidenav'])) {
|
|
33
|
+
throw new Error(`topnav.yaml: duplicate sidenav reference "${obj['sidenav']}".`);
|
|
34
|
+
}
|
|
35
|
+
seenSidenavs.add(obj['sidenav']);
|
|
36
|
+
}
|
|
37
|
+
return raw;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads config/navigation/topnav.yaml and resolves all referenced sidenav files.
|
|
41
|
+
* Returns null if topnav.yaml does not exist (single-sidenav project).
|
|
42
|
+
*
|
|
43
|
+
* @param projectRoot - Absolute path to the project's root directory.
|
|
44
|
+
* @returns The resolved topnav with loaded sidenavs, or null if topnav.yaml is absent.
|
|
45
|
+
*/
|
|
46
|
+
export async function loadTopnavConfig(projectRoot) {
|
|
47
|
+
const filePath = join(projectRoot, TOPNAV_CONFIG_PATH);
|
|
48
|
+
let content;
|
|
49
|
+
try {
|
|
50
|
+
content = await readFile(filePath, 'utf-8');
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
if (err.code === 'ENOENT') {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Failed to read ${filePath}: ${err.message}`);
|
|
57
|
+
}
|
|
58
|
+
let parsed;
|
|
59
|
+
try {
|
|
60
|
+
parsed = yaml.load(content);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw new Error(`Failed to parse ${filePath}: ${err.message}`);
|
|
64
|
+
}
|
|
65
|
+
const topnavItems = validateTopnavConfig(parsed);
|
|
66
|
+
const resolved = [];
|
|
67
|
+
for (const item of topnavItems) {
|
|
68
|
+
const sidenavPath = join(projectRoot, NAV_DIR, item.sidenav);
|
|
69
|
+
const sidenav = await loadSidenavFile(sidenavPath);
|
|
70
|
+
resolved.push({
|
|
71
|
+
label: item.label,
|
|
72
|
+
path: item.path,
|
|
73
|
+
sidenav,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return resolved;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=topnav-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topnav-loader.js","sourceRoot":"","sources":["../../src/config/topnav-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads navigation label translations for all non-default languages from
|
|
3
|
+
* config/navigation/translations/<lang>.yaml. Missing files silently yield
|
|
4
|
+
* an empty map (English labels are shown as fallback).
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadNavTranslations(projectRoot: string, languages: string[], defaultLanguage: string): Promise<Record<string, Record<string, string>>>;
|
|
7
|
+
//# sourceMappingURL=translations-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations-loader.d.ts","sourceRoot":"","sources":["../../src/config/translations-loader.ts"],"names":[],"mappings":"AA2CA;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAUjD"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
const TRANSLATIONS_DIR = join('config', 'navigation', 'translations');
|
|
5
|
+
async function loadTranslationFile(filePath, lang) {
|
|
6
|
+
let content;
|
|
7
|
+
try {
|
|
8
|
+
content = await readFile(filePath, 'utf-8');
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
if (err.code === 'ENOENT')
|
|
12
|
+
return {};
|
|
13
|
+
throw new Error(`Failed to read translation file for "${lang}": ${err.message}`);
|
|
14
|
+
}
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = yaml.load(content);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new Error(`Failed to parse translation file for "${lang}": ${err.message}`);
|
|
21
|
+
}
|
|
22
|
+
if (parsed === null || parsed === undefined)
|
|
23
|
+
return {};
|
|
24
|
+
if (typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
25
|
+
throw new Error(`Translation file for "${lang}" must be a YAML object (label: translation pairs).`);
|
|
26
|
+
}
|
|
27
|
+
const result = {};
|
|
28
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
29
|
+
if (typeof value !== 'string') {
|
|
30
|
+
throw new Error(`Translation file for "${lang}": value for key "${key}" must be a string.`);
|
|
31
|
+
}
|
|
32
|
+
result[key] = value;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Loads navigation label translations for all non-default languages from
|
|
38
|
+
* config/navigation/translations/<lang>.yaml. Missing files silently yield
|
|
39
|
+
* an empty map (English labels are shown as fallback).
|
|
40
|
+
*/
|
|
41
|
+
export async function loadNavTranslations(projectRoot, languages, defaultLanguage) {
|
|
42
|
+
const result = {};
|
|
43
|
+
for (const lang of languages) {
|
|
44
|
+
if (lang === defaultLanguage)
|
|
45
|
+
continue;
|
|
46
|
+
const filePath = join(projectRoot, TRANSLATIONS_DIR, `${lang}.yaml`);
|
|
47
|
+
result[lang] = await loadTranslationFile(filePath, lang);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=translations-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations-loader.js","sourceRoot":"","sources":["../../src/config/translations-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;AAEtE,KAAK,UAAU,mBAAmB,CAAC,QAAgB,EAAE,IAAY;IAC/D,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IAEvD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,qDAAqD,CACnF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;QAC7E,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,qBAAqB,GAAG,qBAAqB,CAC3E,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,SAAmB,EACnB,eAAuB;IAEvB,MAAM,MAAM,GAA2C,EAAE,CAAC;IAE1D,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,IAAI,KAAK,eAAe;YAAE,SAAS;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ContentMap } from '../types/content.js';
|
|
2
|
+
/**
|
|
3
|
+
* Discovers all markdown content files and builds a route manifest.
|
|
4
|
+
*
|
|
5
|
+
* - Scans content/<lang>/ for each language.
|
|
6
|
+
* - Default language routes have no prefix ("/overview"); other languages are prefixed ("/de/overview").
|
|
7
|
+
* - If a declared language has no content directory, it is skipped with a warning (falls back to default at runtime).
|
|
8
|
+
* - Errors if the default language has no content directory or no index.md.
|
|
9
|
+
*
|
|
10
|
+
* @param projectRoot - Absolute path to the project's root directory.
|
|
11
|
+
* @param defaultLanguage - The defaultLanguage value from site.json.
|
|
12
|
+
* @param languages - Array of declared languages from language.json, or null for single-language projects.
|
|
13
|
+
* @returns The content manifest with all discovered entries.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadContent(projectRoot: string, defaultLanguage: string, languages: string[] | null): Promise<ContentMap>;
|
|
16
|
+
//# sourceMappingURL=content-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-loader.d.ts","sourceRoot":"","sources":["../../src/content/content-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAwFpE;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,GACzB,OAAO,CAAC,UAAU,CAAC,CA0DrB"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { readdir, access } from 'node:fs/promises';
|
|
2
|
+
import { join, sep } from 'node:path';
|
|
3
|
+
const CONTENT_DIR = 'content';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether a directory exists on disk.
|
|
6
|
+
*/
|
|
7
|
+
async function dirExists(dirPath) {
|
|
8
|
+
try {
|
|
9
|
+
await access(dirPath);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Recursively finds all .md files in a directory and returns their paths
|
|
18
|
+
* relative to that directory, using forward slashes.
|
|
19
|
+
*/
|
|
20
|
+
async function findMarkdownFiles(dir) {
|
|
21
|
+
let entries;
|
|
22
|
+
try {
|
|
23
|
+
entries = await readdir(dir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const code = err.code;
|
|
27
|
+
if (code === 'ENOENT')
|
|
28
|
+
return [];
|
|
29
|
+
throw new Error(`Failed to read directory ${dir}: ${err.message}`);
|
|
30
|
+
}
|
|
31
|
+
return entries
|
|
32
|
+
.filter((entry) => entry.endsWith('.md'))
|
|
33
|
+
.map((entry) => entry.replaceAll(sep, '/'));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Converts a relative .md file path into a ContentEntry.
|
|
37
|
+
*
|
|
38
|
+
* @param relativePath - Forward-slash path relative to the language dir (e.g. "prerequisites/install-code-editor.md").
|
|
39
|
+
* @param language - The language code (e.g. "en").
|
|
40
|
+
* @param langDir - Absolute path to the language content directory.
|
|
41
|
+
* @param defaultLanguage - The project's default language (no URL prefix for this language).
|
|
42
|
+
*/
|
|
43
|
+
function buildEntry(relativePath, language, langDir, defaultLanguage) {
|
|
44
|
+
const filePath = join(langDir, relativePath.replaceAll('/', sep));
|
|
45
|
+
const withoutExt = relativePath.replace(/\.md$/, '');
|
|
46
|
+
const isIndex = withoutExt.endsWith('/index') || withoutExt === 'index';
|
|
47
|
+
const segments = isIndex
|
|
48
|
+
? withoutExt === 'index' ? [] : withoutExt.replace(/\/index$/, '').split('/')
|
|
49
|
+
: withoutExt.split('/');
|
|
50
|
+
const slug = isIndex
|
|
51
|
+
? 'index'
|
|
52
|
+
: segments[segments.length - 1];
|
|
53
|
+
const prefix = language === defaultLanguage ? '' : `/${language}`;
|
|
54
|
+
const routePath = segments.length === 0
|
|
55
|
+
? prefix || '/'
|
|
56
|
+
: `${prefix}/${segments.join('/')}`;
|
|
57
|
+
return { language, segments, routePath, filePath, slug, isIndex };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Detects route collisions — e.g. both "prerequisites.md" and
|
|
61
|
+
* "prerequisites/index.md" claiming the same route path.
|
|
62
|
+
*/
|
|
63
|
+
function detectCollisions(entries, language) {
|
|
64
|
+
const seen = new Map();
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
const existing = seen.get(entry.routePath);
|
|
67
|
+
if (existing) {
|
|
68
|
+
throw new Error(`Route collision for "${entry.routePath}" in language "${language}": ` +
|
|
69
|
+
`"${existing}" and "${entry.filePath}" both resolve to the same route.`);
|
|
70
|
+
}
|
|
71
|
+
seen.set(entry.routePath, entry.filePath);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Discovers all markdown content files and builds a route manifest.
|
|
76
|
+
*
|
|
77
|
+
* - Scans content/<lang>/ for each language.
|
|
78
|
+
* - Default language routes have no prefix ("/overview"); other languages are prefixed ("/de/overview").
|
|
79
|
+
* - If a declared language has no content directory, it is skipped with a warning (falls back to default at runtime).
|
|
80
|
+
* - Errors if the default language has no content directory or no index.md.
|
|
81
|
+
*
|
|
82
|
+
* @param projectRoot - Absolute path to the project's root directory.
|
|
83
|
+
* @param defaultLanguage - The defaultLanguage value from site.json.
|
|
84
|
+
* @param languages - Array of declared languages from language.json, or null for single-language projects.
|
|
85
|
+
* @returns The content manifest with all discovered entries.
|
|
86
|
+
*/
|
|
87
|
+
export async function loadContent(projectRoot, defaultLanguage, languages) {
|
|
88
|
+
const contentRoot = join(projectRoot, CONTENT_DIR);
|
|
89
|
+
const langCodes = languages ?? [defaultLanguage];
|
|
90
|
+
const allEntries = [];
|
|
91
|
+
const activeLanguages = [];
|
|
92
|
+
for (const lang of langCodes) {
|
|
93
|
+
const langDir = join(contentRoot, lang);
|
|
94
|
+
if (!(await dirExists(langDir))) {
|
|
95
|
+
if (lang === defaultLanguage) {
|
|
96
|
+
throw new Error(`Content directory not found: ${langDir}\n` +
|
|
97
|
+
`Every Mordoc project requires a content/${defaultLanguage}/ directory.`);
|
|
98
|
+
}
|
|
99
|
+
console.warn(`⚠ No content directory for language "${lang}" — ` +
|
|
100
|
+
`content will fall back to "${defaultLanguage}" at runtime.`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const mdFiles = await findMarkdownFiles(langDir);
|
|
104
|
+
if (mdFiles.length === 0) {
|
|
105
|
+
if (lang === defaultLanguage) {
|
|
106
|
+
throw new Error(`No markdown files found in ${langDir}.\n` +
|
|
107
|
+
`The default language content directory must contain at least an index.md file.`);
|
|
108
|
+
}
|
|
109
|
+
console.warn(`⚠ No markdown files in content/${lang}/ — ` +
|
|
110
|
+
`content will fall back to "${defaultLanguage}" at runtime.`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const entries = mdFiles.map((file) => buildEntry(file, lang, langDir, defaultLanguage));
|
|
114
|
+
detectCollisions(entries, lang);
|
|
115
|
+
const hasIndex = entries.some((e) => e.isIndex && e.segments.length === 0);
|
|
116
|
+
if (lang === defaultLanguage && !hasIndex) {
|
|
117
|
+
throw new Error(`Missing content/${defaultLanguage}/index.md.\n` +
|
|
118
|
+
`The default language must have a root index.md — it serves as the landing page.`);
|
|
119
|
+
}
|
|
120
|
+
allEntries.push(...entries);
|
|
121
|
+
activeLanguages.push(lang);
|
|
122
|
+
}
|
|
123
|
+
allEntries.sort((a, b) => a.routePath.localeCompare(b.routePath));
|
|
124
|
+
return { entries: allEntries, languages: activeLanguages };
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=content-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-loader.js","sourceRoot":"","sources":["../../src/content/content-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ContentMap, ParsedPage } from '../types/content.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses all content files from a ContentMap into ASTs plus frontmatter.
|
|
4
|
+
* The TOC and the renderable tree are produced in a later stage
|
|
5
|
+
* (see `content-transformer.ts`) so that anchor IDs stay in sync with
|
|
6
|
+
* what the renderer emits.
|
|
7
|
+
*
|
|
8
|
+
* @param contentMap - The content discovery result from loadContent().
|
|
9
|
+
* @returns An array of parsed pages, one per content entry.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseContent(contentMap: ContentMap): Promise<ParsedPage[]>;
|
|
12
|
+
//# sourceMappingURL=content-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-parser.d.ts","sourceRoot":"","sources":["../../src/content/content-parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAe,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAkC/E;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAoBhF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import Markdoc from '@markdoc/markdoc';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
/**
|
|
5
|
+
* Parses the raw frontmatter YAML string extracted by Markdoc.
|
|
6
|
+
* Validates that at least a title is present.
|
|
7
|
+
*/
|
|
8
|
+
function parseFrontmatter(raw, filePath) {
|
|
9
|
+
if (!raw || raw.trim() === '') {
|
|
10
|
+
throw new Error(`${filePath}: missing frontmatter.\n` +
|
|
11
|
+
`Every content file must have a YAML frontmatter block with at least a "title" field.`);
|
|
12
|
+
}
|
|
13
|
+
let parsed;
|
|
14
|
+
try {
|
|
15
|
+
parsed = yaml.load(raw);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
throw new Error(`${filePath}: invalid frontmatter YAML — ${err.message}`);
|
|
19
|
+
}
|
|
20
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
21
|
+
throw new Error(`${filePath}: frontmatter must be a YAML object.`);
|
|
22
|
+
}
|
|
23
|
+
const obj = parsed;
|
|
24
|
+
if (typeof obj['title'] !== 'string' || obj['title'] === '') {
|
|
25
|
+
throw new Error(`${filePath}: frontmatter "title" is required and must be a non-empty string.`);
|
|
26
|
+
}
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses all content files from a ContentMap into ASTs plus frontmatter.
|
|
31
|
+
* The TOC and the renderable tree are produced in a later stage
|
|
32
|
+
* (see `content-transformer.ts`) so that anchor IDs stay in sync with
|
|
33
|
+
* what the renderer emits.
|
|
34
|
+
*
|
|
35
|
+
* @param contentMap - The content discovery result from loadContent().
|
|
36
|
+
* @returns An array of parsed pages, one per content entry.
|
|
37
|
+
*/
|
|
38
|
+
export async function parseContent(contentMap) {
|
|
39
|
+
const pages = [];
|
|
40
|
+
for (const entry of contentMap.entries) {
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = await readFile(entry.filePath, 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
throw new Error(`Failed to read ${entry.filePath}: ${err.message}`);
|
|
47
|
+
}
|
|
48
|
+
const ast = Markdoc.parse(raw);
|
|
49
|
+
const frontmatter = parseFrontmatter(ast.attributes['frontmatter'], entry.filePath);
|
|
50
|
+
pages.push({ entry, frontmatter, ast });
|
|
51
|
+
}
|
|
52
|
+
return pages;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=content-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-parser.js","sourceRoot":"","sources":["../../src/content/content-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B;;;GAGG;AACH,SAAS,gBAAgB,CAAC,GAAuB,EAAE,QAAgB;IACjE,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,GAAG,QAAQ,0BAA0B;YACrC,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,gCAAiC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,sCAAsC,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAC;IAE9C,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,mEAAmE,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,MAAqB,CAAC;AAC/B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAsB;IACvD,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACvC,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,kBAAkB,KAAK,CAAC,QAAQ,KAAM,GAAa,CAAC,OAAO,EAAE,CAC9D,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAuB,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE1G,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ParsedPage, TransformedPage } from '../types/content.js';
|
|
2
|
+
/**
|
|
3
|
+
* Transforms parsed pages into renderable, JSON-serializable trees.
|
|
4
|
+
*
|
|
5
|
+
* For each page:
|
|
6
|
+
* 1. A fresh slugger is created and attached to a per-page Markdoc config
|
|
7
|
+
* as `variables.slugger`. The heading node transform pulls it out to
|
|
8
|
+
* generate unique anchor IDs within that page.
|
|
9
|
+
* 2. `Markdoc.transform()` runs the AST through the default config.
|
|
10
|
+
* 3. The TOC is derived from the resulting renderable tree so its IDs
|
|
11
|
+
* stay in sync with the rendered headings.
|
|
12
|
+
*
|
|
13
|
+
* The function is synchronous — no I/O happens here; the AST is already
|
|
14
|
+
* in memory from the parse stage.
|
|
15
|
+
*/
|
|
16
|
+
export declare function transformContent(pages: ParsedPage[]): TransformedPage[];
|
|
17
|
+
//# sourceMappingURL=content-transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-transformer.d.ts","sourceRoot":"","sources":["../../src/content/content-transformer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAY,MAAM,qBAAqB,CAAC;AA+CjF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAmCvE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import Markdoc from '@markdoc/markdoc';
|
|
2
|
+
import { createSlugger } from './slug.js';
|
|
3
|
+
import { createDefaultMarkdocConfig } from './markdoc-config.js';
|
|
4
|
+
/**
|
|
5
|
+
* Concatenates the text content of a renderable subtree for TOC display.
|
|
6
|
+
*/
|
|
7
|
+
function extractText(children) {
|
|
8
|
+
let text = '';
|
|
9
|
+
for (const child of children) {
|
|
10
|
+
if (typeof child === 'string')
|
|
11
|
+
text += child;
|
|
12
|
+
else if (Markdoc.Tag.isTag(child))
|
|
13
|
+
text += extractText(child.children);
|
|
14
|
+
}
|
|
15
|
+
return text;
|
|
16
|
+
}
|
|
17
|
+
function walk(node, visit) {
|
|
18
|
+
visit(node);
|
|
19
|
+
if (Markdoc.Tag.isTag(node)) {
|
|
20
|
+
for (const child of node.children)
|
|
21
|
+
walk(child, visit);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Walks the transformed renderable tree and extracts Heading component nodes
|
|
26
|
+
* (level 2–6) into TOC entries. Because this runs after the heading transform,
|
|
27
|
+
* the IDs it reads are exactly the IDs that will appear in the rendered HTML.
|
|
28
|
+
*/
|
|
29
|
+
function extractToc(root) {
|
|
30
|
+
const entries = [];
|
|
31
|
+
walk(root, (node) => {
|
|
32
|
+
if (!Markdoc.Tag.isTag(node))
|
|
33
|
+
return;
|
|
34
|
+
let level = null;
|
|
35
|
+
if (node.name === 'Heading') {
|
|
36
|
+
const l = node.attributes['level'];
|
|
37
|
+
if (typeof l === 'number' && l >= 2 && l <= 6)
|
|
38
|
+
level = l;
|
|
39
|
+
}
|
|
40
|
+
if (level === null)
|
|
41
|
+
return;
|
|
42
|
+
const id = typeof node.attributes['id'] === 'string' ? node.attributes['id'] : '';
|
|
43
|
+
if (id === '')
|
|
44
|
+
return;
|
|
45
|
+
const title = extractText(node.children).trim();
|
|
46
|
+
if (title === '')
|
|
47
|
+
return;
|
|
48
|
+
entries.push({ id, title, level });
|
|
49
|
+
});
|
|
50
|
+
return entries;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Transforms parsed pages into renderable, JSON-serializable trees.
|
|
54
|
+
*
|
|
55
|
+
* For each page:
|
|
56
|
+
* 1. A fresh slugger is created and attached to a per-page Markdoc config
|
|
57
|
+
* as `variables.slugger`. The heading node transform pulls it out to
|
|
58
|
+
* generate unique anchor IDs within that page.
|
|
59
|
+
* 2. `Markdoc.transform()` runs the AST through the default config.
|
|
60
|
+
* 3. The TOC is derived from the resulting renderable tree so its IDs
|
|
61
|
+
* stay in sync with the rendered headings.
|
|
62
|
+
*
|
|
63
|
+
* The function is synchronous — no I/O happens here; the AST is already
|
|
64
|
+
* in memory from the parse stage.
|
|
65
|
+
*/
|
|
66
|
+
export function transformContent(pages) {
|
|
67
|
+
const base = createDefaultMarkdocConfig();
|
|
68
|
+
const out = [];
|
|
69
|
+
for (const page of pages) {
|
|
70
|
+
const slugger = createSlugger();
|
|
71
|
+
const config = {
|
|
72
|
+
...base,
|
|
73
|
+
variables: { ...(base.variables ?? {}), slugger },
|
|
74
|
+
};
|
|
75
|
+
const raw = Markdoc.transform(page.ast, config);
|
|
76
|
+
// `Markdoc.transform` is typed as returning a node-or-array, but when
|
|
77
|
+
// given a parsed document AST it always yields a single root node.
|
|
78
|
+
// Fail loudly if that ever changes rather than silently breaking the
|
|
79
|
+
// TOC and renderer downstream.
|
|
80
|
+
if (Array.isArray(raw)) {
|
|
81
|
+
throw new Error(`Unexpected array result from Markdoc.transform for ${page.entry.filePath}`);
|
|
82
|
+
}
|
|
83
|
+
const renderable = raw;
|
|
84
|
+
const toc = extractToc(renderable);
|
|
85
|
+
out.push({
|
|
86
|
+
entry: page.entry,
|
|
87
|
+
frontmatter: page.frontmatter,
|
|
88
|
+
toc,
|
|
89
|
+
renderable,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=content-transformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-transformer.js","sourceRoot":"","sources":["../../src/content/content-transformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Config } from '@markdoc/markdoc';
|
|
2
|
+
/**
|
|
3
|
+
* The default Markdoc config used by Mordoc's content transformer.
|
|
4
|
+
*
|
|
5
|
+
* Currently minimal:
|
|
6
|
+
* - Custom `heading` node (adds stable, deduplicated anchor IDs).
|
|
7
|
+
* - Custom `fence` node (routes to CodeBlock for syntax highlighting).
|
|
8
|
+
* - Custom `image` node (routes to Image for lightbox support).
|
|
9
|
+
* - Custom `callout` tag (routes to Callout for note/warning/danger boxes).
|
|
10
|
+
* - Custom `card` / `cardGrid` tags (routes to Card / CardGrid components).
|
|
11
|
+
*/
|
|
12
|
+
export declare function createDefaultMarkdocConfig(): Config;
|
|
13
|
+
//# sourceMappingURL=markdoc-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdoc-config.d.ts","sourceRoot":"","sources":["../../src/content/markdoc-config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAA8B,MAAM,kBAAkB,CAAC;AA+M3E;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAKnD"}
|