blume 0.0.0 → 0.1.1
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/bin/blume.mjs +18 -0
- package/dist/cli/index.js +12696 -0
- package/dist/cli/index.js.map +145 -0
- package/dist/types/core/bridge.d.ts +24 -0
- package/dist/types/core/config.d.ts +35 -0
- package/dist/types/core/data.d.ts +129 -0
- package/dist/types/core/define-components.d.ts +27 -0
- package/dist/types/core/define-meta.d.ts +16 -0
- package/dist/types/core/deployment-env.d.ts +9 -0
- package/dist/types/core/diagnostics.d.ts +17 -0
- package/dist/types/core/i18n-ui.d.ts +500 -0
- package/dist/types/core/load-module.d.ts +7 -0
- package/dist/types/core/package-root.d.ts +17 -0
- package/dist/types/core/project.d.ts +9 -0
- package/dist/types/core/schema.d.ts +3451 -0
- package/dist/types/core/sources/types.d.ts +107 -0
- package/dist/types/core/types.d.ts +245 -0
- package/dist/types/core/ui-packs/ar.d.ts +3 -0
- package/dist/types/core/ui-packs/bg.d.ts +3 -0
- package/dist/types/core/ui-packs/bn.d.ts +3 -0
- package/dist/types/core/ui-packs/ca.d.ts +3 -0
- package/dist/types/core/ui-packs/cs.d.ts +3 -0
- package/dist/types/core/ui-packs/da.d.ts +3 -0
- package/dist/types/core/ui-packs/de.d.ts +3 -0
- package/dist/types/core/ui-packs/el.d.ts +3 -0
- package/dist/types/core/ui-packs/es.d.ts +3 -0
- package/dist/types/core/ui-packs/fa.d.ts +3 -0
- package/dist/types/core/ui-packs/fi.d.ts +3 -0
- package/dist/types/core/ui-packs/fr.d.ts +3 -0
- package/dist/types/core/ui-packs/he.d.ts +3 -0
- package/dist/types/core/ui-packs/hi.d.ts +3 -0
- package/dist/types/core/ui-packs/hr.d.ts +3 -0
- package/dist/types/core/ui-packs/hu.d.ts +3 -0
- package/dist/types/core/ui-packs/id.d.ts +3 -0
- package/dist/types/core/ui-packs/index.d.ts +13 -0
- package/dist/types/core/ui-packs/it.d.ts +3 -0
- package/dist/types/core/ui-packs/ja.d.ts +3 -0
- package/dist/types/core/ui-packs/ko.d.ts +3 -0
- package/dist/types/core/ui-packs/nl.d.ts +3 -0
- package/dist/types/core/ui-packs/no.d.ts +3 -0
- package/dist/types/core/ui-packs/pl.d.ts +3 -0
- package/dist/types/core/ui-packs/pt-br.d.ts +3 -0
- package/dist/types/core/ui-packs/pt.d.ts +3 -0
- package/dist/types/core/ui-packs/ro.d.ts +3 -0
- package/dist/types/core/ui-packs/ru.d.ts +3 -0
- package/dist/types/core/ui-packs/sk.d.ts +3 -0
- package/dist/types/core/ui-packs/sr.d.ts +3 -0
- package/dist/types/core/ui-packs/sv.d.ts +3 -0
- package/dist/types/core/ui-packs/th.d.ts +3 -0
- package/dist/types/core/ui-packs/tr.d.ts +3 -0
- package/dist/types/core/ui-packs/uk.d.ts +3 -0
- package/dist/types/core/ui-packs/vi.d.ts +3 -0
- package/dist/types/core/ui-packs/zh-tw.d.ts +3 -0
- package/dist/types/core/ui-packs/zh.d.ts +3 -0
- package/dist/types/core/version.d.ts +8 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/migrate/mintlify/config.d.ts +2 -0
- package/dist/types/migrate/mintlify/i18n.d.ts +7 -0
- package/dist/types/theme/fonts.d.ts +163 -0
- package/docs/01-quickstart.mdx +99 -0
- package/docs/02-deployment.mdx +129 -0
- package/docs/advanced/api-reference.mdx +114 -0
- package/docs/advanced/blog.mdx +121 -0
- package/docs/advanced/changelog.mdx +113 -0
- package/docs/advanced/custom-pages.mdx +268 -0
- package/docs/advanced/meta.ts +7 -0
- package/docs/changelog/v0-1-0.mdx +12 -0
- package/docs/changelog/v0-2-0.mdx +16 -0
- package/docs/configuration/ai.mdx +228 -0
- package/docs/configuration/analytics.mdx +98 -0
- package/docs/configuration/customization.mdx +91 -0
- package/docs/configuration/export.mdx +70 -0
- package/docs/configuration/index.mdx +290 -0
- package/docs/configuration/meta.ts +15 -0
- package/docs/configuration/search.mdx +172 -0
- package/docs/configuration/seo.mdx +196 -0
- package/docs/configuration/theming.mdx +178 -0
- package/docs/content/components.mdx +651 -0
- package/docs/content/i18n.mdx +205 -0
- package/docs/content/index.mdx +161 -0
- package/docs/content/islands.mdx +94 -0
- package/docs/content/meta.mdx +119 -0
- package/docs/content/meta.ts +15 -0
- package/docs/content/navigation.mdx +168 -0
- package/docs/content/sources.mdx +216 -0
- package/docs/content/syntax.mdx +445 -0
- package/docs/index.mdx +112 -0
- package/docs/reference/cli.mdx +43 -0
- package/docs/reference/frontmatter.mdx +74 -0
- package/docs/reference/meta.ts +7 -0
- package/package.json +150 -6
- package/src/ai/ask.ts +93 -0
- package/src/ai/llms.ts +64 -0
- package/src/ai/markdown.ts +31 -0
- package/src/ai/mcp/data.ts +74 -0
- package/src/ai/mcp/discovery.ts +49 -0
- package/src/ai/mcp/server.ts +225 -0
- package/src/ai/mcp/tools.ts +47 -0
- package/src/assets/icon.png +0 -0
- package/src/astro/examples.ts +104 -0
- package/src/astro/generate.ts +1006 -0
- package/src/astro/index.ts +4 -0
- package/src/astro/integration.ts +74 -0
- package/src/astro/islands.ts +131 -0
- package/src/astro/markdown-negotiation.ts +68 -0
- package/src/astro/pages.ts +87 -0
- package/src/astro/templates.ts +1326 -0
- package/src/cli/commands/add.ts +81 -0
- package/src/cli/commands/build.ts +103 -0
- package/src/cli/commands/dev.ts +108 -0
- package/src/cli/commands/doctor.ts +74 -0
- package/src/cli/commands/eject.ts +57 -0
- package/src/cli/commands/init.ts +98 -0
- package/src/cli/commands/migrate.ts +39 -0
- package/src/cli/commands/preview.ts +39 -0
- package/src/cli/commands/sync.ts +52 -0
- package/src/cli/commands/validate.ts +61 -0
- package/src/cli/index.ts +35 -0
- package/src/cli/log.ts +37 -0
- package/src/cli/prepare.ts +80 -0
- package/src/components/Icon.astro +99 -0
- package/src/components/content/Accordion.astro +8 -0
- package/src/components/content/AccordionItem.astro +121 -0
- package/src/components/content/AutoTypeTable.astro +51 -0
- package/src/components/content/Badge.astro +124 -0
- package/src/components/content/Callout.astro +73 -0
- package/src/components/content/Card.astro +104 -0
- package/src/components/content/CardGroup.astro +14 -0
- package/src/components/content/CodeBlock.astro +28 -0
- package/src/components/content/CodeGroup.astro +13 -0
- package/src/components/content/Color.astro +15 -0
- package/src/components/content/ColorItem.astro +87 -0
- package/src/components/content/ColorRow.astro +10 -0
- package/src/components/content/Column.astro +6 -0
- package/src/components/content/Columns.astro +9 -0
- package/src/components/content/Component.astro +65 -0
- package/src/components/content/Diff.astro +44 -0
- package/src/components/content/Expandable.astro +11 -0
- package/src/components/content/FileTree.astro +8 -0
- package/src/components/content/Frame.astro +70 -0
- package/src/components/content/GithubInfo.astro +110 -0
- package/src/components/content/Math.astro +24 -0
- package/src/components/content/Panel.astro +20 -0
- package/src/components/content/Prompt.astro +129 -0
- package/src/components/content/Step.astro +34 -0
- package/src/components/content/Steps.astro +20 -0
- package/src/components/content/Tab.astro +46 -0
- package/src/components/content/Tabs.astro +273 -0
- package/src/components/content/Tile.astro +42 -0
- package/src/components/content/Tooltip.astro +68 -0
- package/src/components/content/Tree.astro +300 -0
- package/src/components/content/TreeFile.astro +15 -0
- package/src/components/content/TreeFolder.astro +62 -0
- package/src/components/content/TypeTable.astro +106 -0
- package/src/components/content/Update.astro +66 -0
- package/src/components/content/Visibility.astro +12 -0
- package/src/components/content/Warning.astro +9 -0
- package/src/components/content/auto-type-table.ts +141 -0
- package/src/components/content/diff.ts +95 -0
- package/src/components/content/github-info.ts +79 -0
- package/src/components/content/mermaid-element.ts +68 -0
- package/src/components/github-mark.ts +9 -0
- package/src/components/index.ts +14 -0
- package/src/components/islands/AskAI.astro +12 -0
- package/src/components/islands/ask-ai.tsx +156 -0
- package/src/components/layout/Analytics.astro +63 -0
- package/src/components/layout/Banner.astro +50 -0
- package/src/components/layout/Breadcrumbs.astro +31 -0
- package/src/components/layout/Favicon.astro +22 -0
- package/src/components/layout/Fonts.astro +14 -0
- package/src/components/layout/Header.astro +188 -0
- package/src/components/layout/LanguageSwitcher.astro +56 -0
- package/src/components/layout/NavTree.astro +462 -0
- package/src/components/layout/PageActions.astro +438 -0
- package/src/components/layout/PageFeedback.astro +58 -0
- package/src/components/layout/PageLayout.astro +173 -0
- package/src/components/layout/Pagination.astro +56 -0
- package/src/components/layout/ReferenceLayout.astro +107 -0
- package/src/components/layout/RootLayout.astro +537 -0
- package/src/components/layout/Search.astro +608 -0
- package/src/components/layout/TableOfContents.astro +68 -0
- package/src/components/layout/analytics-client.ts +38 -0
- package/src/components/layout/head-scripts.ts +19 -0
- package/src/components/layout/nav-utils.ts +87 -0
- package/src/components/layout/overrides.ts +32 -0
- package/src/components/layout/search/algolia.ts +43 -0
- package/src/components/layout/search/endpoint.ts +22 -0
- package/src/components/layout/search/flexsearch.ts +52 -0
- package/src/components/layout/search/orama-cloud.ts +41 -0
- package/src/components/layout/search/orama.ts +26 -0
- package/src/components/layout/search/pagefind.ts +43 -0
- package/src/components/layout/search/types.ts +163 -0
- package/src/components/layout/search/typesense.ts +60 -0
- package/src/components/layout/toc-element.ts +108 -0
- package/src/core/bridge.ts +92 -0
- package/src/core/config.ts +112 -0
- package/src/core/content.ts +50 -0
- package/src/core/data.ts +128 -0
- package/src/core/define-components.ts +34 -0
- package/src/core/define-meta.ts +20 -0
- package/src/core/deployment-env.ts +73 -0
- package/src/core/diagnostics.ts +104 -0
- package/src/core/frontmatter.ts +43 -0
- package/src/core/graph.ts +128 -0
- package/src/core/i18n-ui.ts +171 -0
- package/src/core/i18n.ts +169 -0
- package/src/core/last-modified.ts +88 -0
- package/src/core/links.ts +352 -0
- package/src/core/load-module.ts +15 -0
- package/src/core/manifest.ts +126 -0
- package/src/core/meta.ts +97 -0
- package/src/core/navigation.ts +392 -0
- package/src/core/package-root.ts +37 -0
- package/src/core/project-graph.ts +153 -0
- package/src/core/project.ts +56 -0
- package/src/core/schema.ts +1057 -0
- package/src/core/server-features.ts +23 -0
- package/src/core/sources/assets.ts +77 -0
- package/src/core/sources/cache.ts +122 -0
- package/src/core/sources/filesystem.ts +99 -0
- package/src/core/sources/mdx-remote.ts +215 -0
- package/src/core/sources/mintlify.ts +161 -0
- package/src/core/sources/normalize.ts +243 -0
- package/src/core/sources/notion.ts +440 -0
- package/src/core/sources/portable-text.ts +143 -0
- package/src/core/sources/read.ts +36 -0
- package/src/core/sources/resolve.ts +158 -0
- package/src/core/sources/sanity.ts +218 -0
- package/src/core/sources/types.ts +105 -0
- package/src/core/tsconfig-aliases.ts +201 -0
- package/src/core/types.ts +261 -0
- package/src/core/ui-packs/ar.ts +47 -0
- package/src/core/ui-packs/bg.ts +47 -0
- package/src/core/ui-packs/bn.ts +47 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +47 -0
- package/src/core/ui-packs/da.ts +47 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +47 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +47 -0
- package/src/core/ui-packs/fi.ts +47 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +47 -0
- package/src/core/ui-packs/hi.ts +47 -0
- package/src/core/ui-packs/hr.ts +47 -0
- package/src/core/ui-packs/hu.ts +47 -0
- package/src/core/ui-packs/id.ts +47 -0
- package/src/core/ui-packs/index.ts +87 -0
- package/src/core/ui-packs/it.ts +47 -0
- package/src/core/ui-packs/ja.ts +47 -0
- package/src/core/ui-packs/ko.ts +47 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +47 -0
- package/src/core/ui-packs/pl.ts +47 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +47 -0
- package/src/core/ui-packs/ro.ts +47 -0
- package/src/core/ui-packs/ru.ts +47 -0
- package/src/core/ui-packs/sk.ts +47 -0
- package/src/core/ui-packs/sr.ts +47 -0
- package/src/core/ui-packs/sv.ts +47 -0
- package/src/core/ui-packs/th.ts +47 -0
- package/src/core/ui-packs/tr.ts +47 -0
- package/src/core/ui-packs/uk.ts +47 -0
- package/src/core/ui-packs/vi.ts +47 -0
- package/src/core/ui-packs/zh-tw.ts +47 -0
- package/src/core/ui-packs/zh.ts +47 -0
- package/src/core/version.ts +23 -0
- package/src/deploy/robots.ts +20 -0
- package/src/deploy/rss.ts +128 -0
- package/src/deploy/sitemap.ts +28 -0
- package/src/index.ts +39 -0
- package/src/markdown/code-title.ts +71 -0
- package/src/markdown/directives.ts +83 -0
- package/src/markdown/heading-anchors.ts +137 -0
- package/src/markdown/index.ts +228 -0
- package/src/markdown/inline-code.ts +108 -0
- package/src/markdown/language-icon.ts +172 -0
- package/src/markdown/math.ts +32 -0
- package/src/markdown/mdast.ts +48 -0
- package/src/markdown/mermaid.ts +37 -0
- package/src/markdown/package-commands.ts +159 -0
- package/src/markdown/package-install.ts +40 -0
- package/src/migrate/fumadocs/config.ts +155 -0
- package/src/migrate/fumadocs/content.ts +365 -0
- package/src/migrate/fumadocs/frontmatter.ts +18 -0
- package/src/migrate/fumadocs/groups.ts +230 -0
- package/src/migrate/fumadocs/index.ts +337 -0
- package/src/migrate/fumadocs/meta.ts +244 -0
- package/src/migrate/migrate.ts +53 -0
- package/src/migrate/mintlify/config.ts +1040 -0
- package/src/migrate/mintlify/content.ts +98 -0
- package/src/migrate/mintlify/frontmatter.ts +126 -0
- package/src/migrate/mintlify/i18n.ts +51 -0
- package/src/migrate/mintlify/icons.ts +128 -0
- package/src/migrate/mintlify/index.ts +266 -0
- package/src/migrate/mintlify/snippets.ts +306 -0
- package/src/migrate/mintlify/transform.ts +80 -0
- package/src/migrate/nextra/content.ts +46 -0
- package/src/migrate/nextra/frontmatter.ts +40 -0
- package/src/migrate/nextra/index.ts +374 -0
- package/src/migrate/nextra/meta.ts +266 -0
- package/src/migrate/shared.ts +720 -0
- package/src/migrate/starlight/config.ts +459 -0
- package/src/migrate/starlight/content.ts +78 -0
- package/src/migrate/starlight/frontmatter.ts +111 -0
- package/src/migrate/starlight/i18n.ts +54 -0
- package/src/migrate/starlight/index.ts +131 -0
- package/src/og/card.ts +92 -0
- package/src/og/index.ts +2 -0
- package/src/openapi/scalar.ts +246 -0
- package/src/registry/eject.ts +310 -0
- package/src/registry/registry.ts +100 -0
- package/src/registry/rewrite-imports.ts +39 -0
- package/src/runtime/index.ts +14 -0
- package/src/search/build.ts +23 -0
- package/src/search/documents.ts +164 -0
- package/src/search/orama-index.ts +66 -0
- package/src/search/providers.ts +91 -0
- package/src/search/sync/algolia.ts +30 -0
- package/src/search/sync/index.ts +50 -0
- package/src/search/sync/orama-cloud.ts +40 -0
- package/src/search/sync/typesense.ts +65 -0
- package/src/seo/jsonld.ts +113 -0
- package/src/theme/entry.ts +637 -0
- package/src/theme/fonts.ts +198 -0
- package/src/theme/icons.ts +184 -0
- package/src/theme/palette.ts +143 -0
- package/src/theme/twoslash.ts +81 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Shiki transformer that prepends a brand icon to a code block's header,
|
|
3
|
+
* keyed off the fence language. Icons are sourced from `simple-icons` (raw SVG
|
|
4
|
+
* path data) at build time and emitted as an inline `<svg>` — no client JS and
|
|
5
|
+
* no React, so it works in the core theme. The icon renders in `currentColor`
|
|
6
|
+
* (the muted header color) so it stays legible in both light and dark; brand
|
|
7
|
+
* hex colors are skipped because dark-on-dark logos (Next.js, Rust…) vanish.
|
|
8
|
+
*
|
|
9
|
+
* The theme styles `.blume-lang-icon` and shifts the language label
|
|
10
|
+
* (`pre[data-icon]::before`) to make room.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
siAstro,
|
|
15
|
+
siC,
|
|
16
|
+
siCplusplus,
|
|
17
|
+
siCss3,
|
|
18
|
+
siDart,
|
|
19
|
+
siDocker,
|
|
20
|
+
siGnubash,
|
|
21
|
+
siGo,
|
|
22
|
+
siGraphql,
|
|
23
|
+
siHtml5,
|
|
24
|
+
siJavascript,
|
|
25
|
+
siJson,
|
|
26
|
+
siKotlin,
|
|
27
|
+
siLess,
|
|
28
|
+
siLua,
|
|
29
|
+
siMarkdown,
|
|
30
|
+
siMdx,
|
|
31
|
+
siMysql,
|
|
32
|
+
siNextdotjs,
|
|
33
|
+
siPhp,
|
|
34
|
+
siPrisma,
|
|
35
|
+
siPython,
|
|
36
|
+
siReact,
|
|
37
|
+
siRuby,
|
|
38
|
+
siRust,
|
|
39
|
+
siSass,
|
|
40
|
+
siScala,
|
|
41
|
+
siSvelte,
|
|
42
|
+
siSvg,
|
|
43
|
+
siSwift,
|
|
44
|
+
siToml,
|
|
45
|
+
siTypescript,
|
|
46
|
+
siVuedotjs,
|
|
47
|
+
siWebassembly,
|
|
48
|
+
siYaml,
|
|
49
|
+
} from "simple-icons";
|
|
50
|
+
|
|
51
|
+
/** The slice of a `simple-icons` icon Blume reads (the SVG path data). */
|
|
52
|
+
interface SimpleIcon {
|
|
53
|
+
path: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Fence language (and common aliases) → icon. Unmapped languages get none. */
|
|
57
|
+
const LANGUAGE_ICONS: Record<string, SimpleIcon> = {
|
|
58
|
+
astro: siAstro,
|
|
59
|
+
bash: siGnubash,
|
|
60
|
+
c: siC,
|
|
61
|
+
"c++": siCplusplus,
|
|
62
|
+
cjs: siJavascript,
|
|
63
|
+
cpp: siCplusplus,
|
|
64
|
+
css: siCss3,
|
|
65
|
+
cts: siTypescript,
|
|
66
|
+
dart: siDart,
|
|
67
|
+
docker: siDocker,
|
|
68
|
+
dockerfile: siDocker,
|
|
69
|
+
go: siGo,
|
|
70
|
+
gql: siGraphql,
|
|
71
|
+
graphql: siGraphql,
|
|
72
|
+
html: siHtml5,
|
|
73
|
+
javascript: siJavascript,
|
|
74
|
+
js: siJavascript,
|
|
75
|
+
json: siJson,
|
|
76
|
+
json5: siJson,
|
|
77
|
+
jsonc: siJson,
|
|
78
|
+
jsx: siReact,
|
|
79
|
+
kotlin: siKotlin,
|
|
80
|
+
kt: siKotlin,
|
|
81
|
+
less: siLess,
|
|
82
|
+
lua: siLua,
|
|
83
|
+
markdown: siMarkdown,
|
|
84
|
+
md: siMarkdown,
|
|
85
|
+
mdx: siMdx,
|
|
86
|
+
mjs: siJavascript,
|
|
87
|
+
mts: siTypescript,
|
|
88
|
+
nextjs: siNextdotjs,
|
|
89
|
+
php: siPhp,
|
|
90
|
+
prisma: siPrisma,
|
|
91
|
+
py: siPython,
|
|
92
|
+
python: siPython,
|
|
93
|
+
rb: siRuby,
|
|
94
|
+
react: siReact,
|
|
95
|
+
rs: siRust,
|
|
96
|
+
ruby: siRuby,
|
|
97
|
+
rust: siRust,
|
|
98
|
+
sass: siSass,
|
|
99
|
+
scala: siScala,
|
|
100
|
+
scss: siSass,
|
|
101
|
+
sh: siGnubash,
|
|
102
|
+
shell: siGnubash,
|
|
103
|
+
sql: siMysql,
|
|
104
|
+
svelte: siSvelte,
|
|
105
|
+
svg: siSvg,
|
|
106
|
+
swift: siSwift,
|
|
107
|
+
toml: siToml,
|
|
108
|
+
ts: siTypescript,
|
|
109
|
+
tsx: siReact,
|
|
110
|
+
typescript: siTypescript,
|
|
111
|
+
vue: siVuedotjs,
|
|
112
|
+
wasm: siWebassembly,
|
|
113
|
+
yaml: siYaml,
|
|
114
|
+
yml: siYaml,
|
|
115
|
+
zsh: siGnubash,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** A minimal hast node (avoids a hast type dependency). */
|
|
119
|
+
interface HastNode {
|
|
120
|
+
children?: HastNode[];
|
|
121
|
+
properties?: Record<string, unknown>;
|
|
122
|
+
tagName?: string;
|
|
123
|
+
type: string;
|
|
124
|
+
value?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The slice of Shiki's transformer `this` context the icon hook reads. */
|
|
128
|
+
interface IconContext {
|
|
129
|
+
options: { lang?: string };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** The `<pre>` hast node a Shiki `pre` hook receives. */
|
|
133
|
+
interface IconPreNode {
|
|
134
|
+
children: HastNode[];
|
|
135
|
+
properties: Record<string, boolean | number | string | undefined>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** A Shiki-compatible transformer, typed structurally to avoid a Shiki dep. */
|
|
139
|
+
export interface LanguageIconTransformer {
|
|
140
|
+
name: string;
|
|
141
|
+
pre: (this: IconContext, node: IconPreNode) => void;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Build an inline SVG hast node from a simple-icons path. */
|
|
145
|
+
const iconNode = (path: string): HastNode => ({
|
|
146
|
+
children: [
|
|
147
|
+
{ children: [], properties: { d: path }, tagName: "path", type: "element" },
|
|
148
|
+
],
|
|
149
|
+
properties: {
|
|
150
|
+
ariaHidden: "true",
|
|
151
|
+
className: ["blume-lang-icon"],
|
|
152
|
+
fill: "currentColor",
|
|
153
|
+
height: 14,
|
|
154
|
+
viewBox: "0 0 24 24",
|
|
155
|
+
width: 14,
|
|
156
|
+
},
|
|
157
|
+
tagName: "svg",
|
|
158
|
+
type: "element",
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
/** Build the transformer. Runs after Shiki's built-in `data-language` hook. */
|
|
162
|
+
export const languageIconTransformer = (): LanguageIconTransformer => ({
|
|
163
|
+
name: "blume:language-icon",
|
|
164
|
+
pre(node) {
|
|
165
|
+
const icon = LANGUAGE_ICONS[(this.options.lang ?? "").toLowerCase()];
|
|
166
|
+
if (!icon) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
node.children.unshift(iconNode(icon.path));
|
|
170
|
+
node.properties.dataIcon = "";
|
|
171
|
+
},
|
|
172
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsxAttribute, jsxFlowElement, jsxTextElement } from "./mdast.ts";
|
|
2
|
+
import type { MdastNode, MdastVisitorContext } from "./mdast.ts";
|
|
3
|
+
|
|
4
|
+
interface MathNode extends MdastNode {
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Satteri MDAST plugin that turns math nodes into Blume's `<Math>` component,
|
|
10
|
+
* which renders them with KaTeX at build time. Block math (`$$…$$`) becomes a
|
|
11
|
+
* block element; inline math (`$…$`) stays inline. Only active when math is
|
|
12
|
+
* enabled in config, so `$` is otherwise left as literal text.
|
|
13
|
+
*/
|
|
14
|
+
export const mathPlugin = () => ({
|
|
15
|
+
inlineMath(node: MathNode, ctx: MdastVisitorContext) {
|
|
16
|
+
ctx.replaceNode(
|
|
17
|
+
node,
|
|
18
|
+
jsxTextElement("Math", [jsxAttribute("code", node.value)])
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
math(node: MathNode, ctx: MdastVisitorContext) {
|
|
22
|
+
ctx.replaceNode(
|
|
23
|
+
node,
|
|
24
|
+
jsxFlowElement(
|
|
25
|
+
"Math",
|
|
26
|
+
[jsxAttribute("code", node.value), jsxAttribute("display")],
|
|
27
|
+
[]
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
},
|
|
31
|
+
name: "blume-math",
|
|
32
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal structural types and node builders for the (alpha) Satteri MDAST
|
|
3
|
+
* plugin API. We model only what Blume's plugins read and construct; the full
|
|
4
|
+
* types live in `satteri`, a transitive dependency. Plugins are bridged to
|
|
5
|
+
* Satteri's real `MdastPlugin` type at a single boundary in `index.ts`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** The visitor context Blume's plugins use to mutate the tree. */
|
|
9
|
+
export interface MdastVisitorContext {
|
|
10
|
+
replaceNode: (node: unknown, replacement: unknown) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Any MDAST node, keyed loosely since we build a small subset by hand. */
|
|
14
|
+
export interface MdastNode {
|
|
15
|
+
type: string;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Build an MDX JSX attribute. A `null` value renders as a boolean attribute. */
|
|
20
|
+
export const jsxAttribute = (name: string, value: string | null = null) => ({
|
|
21
|
+
name,
|
|
22
|
+
type: "mdxJsxAttribute",
|
|
23
|
+
value,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
type JsxAttribute = ReturnType<typeof jsxAttribute>;
|
|
27
|
+
|
|
28
|
+
/** Build a block-level MDX JSX element (`<Name>…</Name>`). */
|
|
29
|
+
export const jsxFlowElement = (
|
|
30
|
+
name: string,
|
|
31
|
+
attributes: JsxAttribute[],
|
|
32
|
+
children: unknown[]
|
|
33
|
+
) => ({ attributes, children, name, type: "mdxJsxFlowElement" });
|
|
34
|
+
|
|
35
|
+
/** Build an inline MDX JSX element (phrasing context). */
|
|
36
|
+
export const jsxTextElement = (
|
|
37
|
+
name: string,
|
|
38
|
+
attributes: JsxAttribute[],
|
|
39
|
+
children: unknown[] = []
|
|
40
|
+
) => ({ attributes, children, name, type: "mdxJsxTextElement" });
|
|
41
|
+
|
|
42
|
+
/** Build a fenced code block node. */
|
|
43
|
+
export const codeBlock = (lang: string, value: string) => ({
|
|
44
|
+
lang,
|
|
45
|
+
meta: null,
|
|
46
|
+
type: "code",
|
|
47
|
+
value,
|
|
48
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsxAttribute, jsxFlowElement } from "./mdast.ts";
|
|
2
|
+
import type { MdastNode, MdastVisitorContext } from "./mdast.ts";
|
|
3
|
+
|
|
4
|
+
interface CodeNode extends MdastNode {
|
|
5
|
+
lang?: string | null;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Satteri MDAST plugin that turns a ` ```mermaid ` code block into a
|
|
11
|
+
* `<blume-mermaid>` custom element carrying the raw diagram source. There is no
|
|
12
|
+
* importable component — the fence is the whole interface. The element is
|
|
13
|
+
* rendered on the client (Mermaid needs a DOM), so the source rides on a string
|
|
14
|
+
* attribute rather than as child text (which MDX would try to parse).
|
|
15
|
+
*/
|
|
16
|
+
export const mermaidPlugin = () => ({
|
|
17
|
+
code(node: CodeNode, ctx: MdastVisitorContext) {
|
|
18
|
+
if (node.lang !== "mermaid") {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
ctx.replaceNode(
|
|
22
|
+
node,
|
|
23
|
+
jsxFlowElement(
|
|
24
|
+
"blume-mermaid",
|
|
25
|
+
[
|
|
26
|
+
jsxAttribute(
|
|
27
|
+
"class",
|
|
28
|
+
"not-prose my-6 flex justify-center overflow-x-auto"
|
|
29
|
+
),
|
|
30
|
+
jsxAttribute("data-source", node.value),
|
|
31
|
+
],
|
|
32
|
+
[]
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
},
|
|
36
|
+
name: "blume-mermaid",
|
|
37
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/** Supported package managers, in the order tabs are displayed. */
|
|
2
|
+
export const PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"] as const;
|
|
3
|
+
|
|
4
|
+
export type PackageManager = (typeof PACKAGE_MANAGERS)[number];
|
|
5
|
+
|
|
6
|
+
/** Words that mark the input as an explicit command rather than a bare list. */
|
|
7
|
+
const MANAGER_PREFIXES = new Set(["bun", "bunx", "npm", "npx", "pnpm", "yarn"]);
|
|
8
|
+
|
|
9
|
+
const WHITESPACE = /\s+/u;
|
|
10
|
+
const WHITESPACE_RUN = /\s+/gu;
|
|
11
|
+
const GLOBAL_FLAGS = new Set(["-g", "--global"]);
|
|
12
|
+
|
|
13
|
+
type Operation = "add" | "create" | "exec" | "install" | "remove" | "run";
|
|
14
|
+
|
|
15
|
+
interface Intent {
|
|
16
|
+
args: string[];
|
|
17
|
+
operation: Operation;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Map a package-manager subcommand to a normalized operation. */
|
|
21
|
+
const normalizeVerb = (verb: string): Operation | null => {
|
|
22
|
+
switch (verb) {
|
|
23
|
+
case "add":
|
|
24
|
+
case "i":
|
|
25
|
+
case "in":
|
|
26
|
+
case "install": {
|
|
27
|
+
return "add";
|
|
28
|
+
}
|
|
29
|
+
case "create":
|
|
30
|
+
case "init": {
|
|
31
|
+
return "create";
|
|
32
|
+
}
|
|
33
|
+
case "dlx":
|
|
34
|
+
case "exec":
|
|
35
|
+
case "x": {
|
|
36
|
+
return "exec";
|
|
37
|
+
}
|
|
38
|
+
case "remove":
|
|
39
|
+
case "rm":
|
|
40
|
+
case "un":
|
|
41
|
+
case "uninstall": {
|
|
42
|
+
return "remove";
|
|
43
|
+
}
|
|
44
|
+
case "run": {
|
|
45
|
+
return "run";
|
|
46
|
+
}
|
|
47
|
+
default: {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Normalize npm-style flags to forms every manager understands. */
|
|
54
|
+
const normalizeFlags = (args: string[]): string[] =>
|
|
55
|
+
args.flatMap((arg) => {
|
|
56
|
+
if (arg === "--save-dev") {
|
|
57
|
+
return ["-D"];
|
|
58
|
+
}
|
|
59
|
+
if (arg === "--save" || arg === "-S") {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return [arg];
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse an input command (a bare package list like `react react-dom` or an
|
|
67
|
+
* explicit command like `npm i -D typescript` / `npx astro add`) into a
|
|
68
|
+
* manager-agnostic intent.
|
|
69
|
+
*/
|
|
70
|
+
const parseIntent = (input: string): Intent => {
|
|
71
|
+
const tokens = input.trim().split(WHITESPACE).filter(Boolean);
|
|
72
|
+
if (tokens.length === 0) {
|
|
73
|
+
return { args: [], operation: "install" };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const [first, ...rest] = tokens;
|
|
77
|
+
if (first === undefined) {
|
|
78
|
+
return { args: [], operation: "install" };
|
|
79
|
+
}
|
|
80
|
+
if (!MANAGER_PREFIXES.has(first)) {
|
|
81
|
+
return { args: normalizeFlags(tokens), operation: "add" };
|
|
82
|
+
}
|
|
83
|
+
if (first === "npx" || first === "bunx") {
|
|
84
|
+
return { args: rest, operation: "exec" };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const [verb, ...verbArgs] = rest;
|
|
88
|
+
if (!verb) {
|
|
89
|
+
return { args: [], operation: "install" };
|
|
90
|
+
}
|
|
91
|
+
const operation = normalizeVerb(verb);
|
|
92
|
+
if (operation === null) {
|
|
93
|
+
// Unknown subcommand (e.g. `npm test`); run it as a script.
|
|
94
|
+
return { args: rest, operation: "run" };
|
|
95
|
+
}
|
|
96
|
+
if (operation === "add" && verbArgs.length === 0) {
|
|
97
|
+
return { args: [], operation: "install" };
|
|
98
|
+
}
|
|
99
|
+
return { args: normalizeFlags(verbArgs), operation };
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/** Render one manager's command for the given intent. */
|
|
103
|
+
const buildCommand = (manager: PackageManager, intent: Intent): string => {
|
|
104
|
+
const args = intent.args.join(" ");
|
|
105
|
+
switch (intent.operation) {
|
|
106
|
+
case "add": {
|
|
107
|
+
if (manager === "npm") {
|
|
108
|
+
return `npm install ${args}`;
|
|
109
|
+
}
|
|
110
|
+
if (manager === "yarn" && intent.args.some((a) => GLOBAL_FLAGS.has(a))) {
|
|
111
|
+
const pkgs = intent.args.filter((a) => !GLOBAL_FLAGS.has(a)).join(" ");
|
|
112
|
+
return `yarn global add ${pkgs}`;
|
|
113
|
+
}
|
|
114
|
+
return `${manager} add ${args}`;
|
|
115
|
+
}
|
|
116
|
+
case "create": {
|
|
117
|
+
return `${manager} create ${args}`;
|
|
118
|
+
}
|
|
119
|
+
case "exec": {
|
|
120
|
+
if (manager === "npm") {
|
|
121
|
+
return `npx ${args}`;
|
|
122
|
+
}
|
|
123
|
+
if (manager === "bun") {
|
|
124
|
+
return `bunx ${args}`;
|
|
125
|
+
}
|
|
126
|
+
return `${manager} dlx ${args}`;
|
|
127
|
+
}
|
|
128
|
+
case "remove": {
|
|
129
|
+
return manager === "npm"
|
|
130
|
+
? `npm uninstall ${args}`
|
|
131
|
+
: `${manager} remove ${args}`;
|
|
132
|
+
}
|
|
133
|
+
case "run": {
|
|
134
|
+
return `${manager} run ${args}`;
|
|
135
|
+
}
|
|
136
|
+
default: {
|
|
137
|
+
return `${manager} install`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Convert an install command into the equivalent for every supported package
|
|
144
|
+
* manager. Accepts a bare package list (`react`) or a full command
|
|
145
|
+
* (`npm i -D typescript`, `npx astro add react`).
|
|
146
|
+
*/
|
|
147
|
+
export const toPackageCommands = (
|
|
148
|
+
input: string
|
|
149
|
+
): Record<PackageManager, string> => {
|
|
150
|
+
const intent = parseIntent(input);
|
|
151
|
+
const normalize = (command: string): string =>
|
|
152
|
+
command.replaceAll(WHITESPACE_RUN, " ").trim();
|
|
153
|
+
return {
|
|
154
|
+
bun: normalize(buildCommand("bun", intent)),
|
|
155
|
+
npm: normalize(buildCommand("npm", intent)),
|
|
156
|
+
pnpm: normalize(buildCommand("pnpm", intent)),
|
|
157
|
+
yarn: normalize(buildCommand("yarn", intent)),
|
|
158
|
+
};
|
|
159
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { codeBlock, jsxAttribute, jsxFlowElement } from "./mdast.ts";
|
|
2
|
+
import type { MdastNode, MdastVisitorContext } from "./mdast.ts";
|
|
3
|
+
import { PACKAGE_MANAGERS, toPackageCommands } from "./package-commands.ts";
|
|
4
|
+
|
|
5
|
+
interface CodeNode extends MdastNode {
|
|
6
|
+
lang?: string | null;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Build an `<Tab title="...">` node wrapping a single highlighted command. */
|
|
11
|
+
const tabNode = (manager: string, command: string) =>
|
|
12
|
+
jsxFlowElement(
|
|
13
|
+
"Tab",
|
|
14
|
+
[jsxAttribute("title", manager)],
|
|
15
|
+
[codeBlock("bash", command)]
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Satteri MDAST plugin that turns a ` ```package-install ` code block into a
|
|
20
|
+
* `<Tabs>` group with one `<Tab>` per package manager, each holding the
|
|
21
|
+
* converted install command as a normal (highlighted) code block. Runs at the
|
|
22
|
+
* MDAST stage so the generated code blocks are highlighted like any other.
|
|
23
|
+
*/
|
|
24
|
+
export const packageInstallPlugin = () => ({
|
|
25
|
+
code(node: CodeNode, ctx: MdastVisitorContext) {
|
|
26
|
+
if (node.lang !== "package-install") {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const commands = toPackageCommands(node.value);
|
|
30
|
+
ctx.replaceNode(
|
|
31
|
+
node,
|
|
32
|
+
jsxFlowElement(
|
|
33
|
+
"Tabs",
|
|
34
|
+
[],
|
|
35
|
+
PACKAGE_MANAGERS.map((manager) => tabNode(manager, commands[manager]))
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
name: "blume-package-install",
|
|
40
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
import { basename, dirname, join } from "pathe";
|
|
5
|
+
|
|
6
|
+
import type { BlumeConfig } from "../../core/schema.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build a `BlumeConfig` for a Fumadocs project. Fumadocs is code-first — its
|
|
10
|
+
* navigation comes from the folder tree plus `meta.json` files, not a JSON
|
|
11
|
+
* config — so there is little to translate. We take the title from
|
|
12
|
+
* `package.json` and scrape the `loader({ baseUrl })` route prefix from the
|
|
13
|
+
* source loader so migrated routes keep serving under `/<baseUrl>`. The source
|
|
14
|
+
* files are TypeScript, so we read by pattern rather than executing them.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Loader files that may hold `loader({ baseUrl: "/docs" })`. */
|
|
18
|
+
const SOURCE_FILES = [
|
|
19
|
+
"lib/source.ts",
|
|
20
|
+
"app/source.ts",
|
|
21
|
+
"src/lib/source.ts",
|
|
22
|
+
"src/app/source.ts",
|
|
23
|
+
"source.ts",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const BASE_URL = /baseUrl\s*:\s*['"`](?<base>[^'"`]+)['"`]/u;
|
|
27
|
+
|
|
28
|
+
/** Title-case a package name (drop any scope) into a readable doc title. */
|
|
29
|
+
const prettifyTitle = (name: string): string => {
|
|
30
|
+
const base = name.includes("/")
|
|
31
|
+
? name.slice(name.lastIndexOf("/") + 1)
|
|
32
|
+
: name;
|
|
33
|
+
const words = base.split(/[-_\s]+/u).filter(Boolean);
|
|
34
|
+
if (words.length === 0) {
|
|
35
|
+
return "Documentation";
|
|
36
|
+
}
|
|
37
|
+
return words
|
|
38
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
39
|
+
.join(" ");
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generic monorepo app-shell package names. When the migrated project is named
|
|
44
|
+
* one of these, its name makes a poor doc title ("Web"), so we fall back to the
|
|
45
|
+
* repo name — but only in a monorepo, where a better name is actually available.
|
|
46
|
+
*/
|
|
47
|
+
const GENERIC_NAMES = new Set([
|
|
48
|
+
"api",
|
|
49
|
+
"app",
|
|
50
|
+
"client",
|
|
51
|
+
"frontend",
|
|
52
|
+
"server",
|
|
53
|
+
"site",
|
|
54
|
+
"web",
|
|
55
|
+
"www",
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
/** The nearest ancestor that is a git repository root, or null. */
|
|
59
|
+
const gitRepoRoot = (start: string): string | null => {
|
|
60
|
+
let dir = start;
|
|
61
|
+
for (;;) {
|
|
62
|
+
if (existsSync(join(dir, ".git"))) {
|
|
63
|
+
return dir;
|
|
64
|
+
}
|
|
65
|
+
const parent = dirname(dir);
|
|
66
|
+
if (parent === dir) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
dir = parent;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** The unscoped package name (`@acme/web` -> `web`). */
|
|
74
|
+
const bareName = (name: string): string =>
|
|
75
|
+
name.includes("/") ? name.slice(name.lastIndexOf("/") + 1) : name;
|
|
76
|
+
|
|
77
|
+
const readTitle = async (root: string): Promise<string> => {
|
|
78
|
+
const packageJson = join(root, "package.json");
|
|
79
|
+
if (!existsSync(packageJson)) {
|
|
80
|
+
return "Documentation";
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(await readFile(packageJson, "utf-8")) as {
|
|
84
|
+
name?: unknown;
|
|
85
|
+
};
|
|
86
|
+
const { name } = parsed;
|
|
87
|
+
if (typeof name !== "string" || !name.trim()) {
|
|
88
|
+
return "Documentation";
|
|
89
|
+
}
|
|
90
|
+
// A generic name (`apps/web` -> "Web") is a weak title. In a monorepo the
|
|
91
|
+
// repo's own directory name is usually better, so prefer it when this isn't
|
|
92
|
+
// already the repo root.
|
|
93
|
+
if (GENERIC_NAMES.has(bareName(name).toLowerCase())) {
|
|
94
|
+
const repoRoot = gitRepoRoot(root);
|
|
95
|
+
if (repoRoot && repoRoot !== root) {
|
|
96
|
+
const repoTitle = prettifyTitle(basename(repoRoot));
|
|
97
|
+
if (repoTitle !== "Documentation") {
|
|
98
|
+
return repoTitle;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return prettifyTitle(name);
|
|
103
|
+
} catch {
|
|
104
|
+
return "Documentation";
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const scrapeBaseUrl = async (root: string): Promise<string | null> => {
|
|
109
|
+
for (const candidate of SOURCE_FILES) {
|
|
110
|
+
const file = join(root, candidate);
|
|
111
|
+
if (!existsSync(file)) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// oxlint-disable-next-line no-await-in-loop -- sequential probing of candidates
|
|
115
|
+
const base = BASE_URL.exec(await readFile(file, "utf-8"))?.groups?.base;
|
|
116
|
+
if (base) {
|
|
117
|
+
return base;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export interface FumadocsConfigResult {
|
|
124
|
+
config: BlumeConfig;
|
|
125
|
+
warnings: string[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Resolve the Blume config and route prefix for a Fumadocs project. */
|
|
129
|
+
export const loadFumadocsConfig = async (
|
|
130
|
+
root: string
|
|
131
|
+
): Promise<FumadocsConfigResult> => {
|
|
132
|
+
const title = await readTitle(root);
|
|
133
|
+
const baseUrl = await scrapeBaseUrl(root);
|
|
134
|
+
// Default to the conventional Fumadocs `/docs` base when none is declared.
|
|
135
|
+
const prefix = (baseUrl ?? "docs").replaceAll(/^\/+|\/+$/gu, "");
|
|
136
|
+
const warnings: string[] = [];
|
|
137
|
+
|
|
138
|
+
if (prefix) {
|
|
139
|
+
warnings.push(
|
|
140
|
+
`Docs are served under /${prefix} (set content.sources prefix); change it to "" to serve from the site root.`
|
|
141
|
+
);
|
|
142
|
+
return {
|
|
143
|
+
config: {
|
|
144
|
+
content: {
|
|
145
|
+
sources: [{ prefix, root: "docs", type: "filesystem" }],
|
|
146
|
+
},
|
|
147
|
+
title,
|
|
148
|
+
},
|
|
149
|
+
warnings,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
warnings.push("Docs are served from the site root.");
|
|
154
|
+
return { config: { title }, warnings };
|
|
155
|
+
};
|