blume 2.1.3 → 2.2.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/AGENTS.md +1 -1
- package/CHANGELOG.md +126 -0
- package/README.md +4 -4
- package/dist/cli/{chunk-74wfhv79.js → chunk-05f21r8h.js} +1 -1
- package/dist/cli/{chunk-9qzgg6mj.js → chunk-1cm0h819.js} +3 -3
- package/dist/cli/{chunk-nbyvgnnm.js → chunk-1rkxzg3n.js} +104 -47
- package/dist/cli/chunk-1rkxzg3n.js.map +36 -0
- package/dist/cli/{chunk-desvm72z.js → chunk-2nr29y95.js} +22 -26
- package/dist/cli/chunk-2nr29y95.js.map +13 -0
- package/dist/cli/{chunk-32khwcb6.js → chunk-49r370mb.js} +42 -69
- package/dist/cli/{chunk-32khwcb6.js.map → chunk-49r370mb.js.map} +9 -10
- package/dist/cli/{chunk-ms9z66nz.js → chunk-4rftmttv.js} +2 -2
- package/dist/cli/{chunk-s0bdnc7v.js → chunk-79bzzkx4.js} +5 -4
- package/dist/cli/chunk-79bzzkx4.js.map +10 -0
- package/dist/cli/{chunk-hvcxng5f.js → chunk-7tekknev.js} +6 -6
- package/dist/cli/{chunk-dv2z0rzf.js → chunk-8b489v1b.js} +38 -13
- package/dist/cli/{chunk-dv2z0rzf.js.map → chunk-8b489v1b.js.map} +5 -4
- package/dist/cli/{chunk-0pmb4tr4.js → chunk-8f8xw4x2.js} +1195 -222
- package/dist/cli/chunk-8f8xw4x2.js.map +44 -0
- package/dist/cli/chunk-96snx8yy.js +329 -0
- package/dist/cli/chunk-96snx8yy.js.map +13 -0
- package/dist/cli/{chunk-ckrcm08h.js → chunk-a3ydrqny.js} +48 -62
- package/dist/cli/{chunk-ckrcm08h.js.map → chunk-a3ydrqny.js.map} +4 -5
- package/dist/cli/{chunk-bxwhtvw8.js → chunk-ahc5gc9h.js} +5 -5
- package/dist/cli/{chunk-dpy8qdjf.js → chunk-as09pafp.js} +73 -182
- package/dist/cli/chunk-as09pafp.js.map +18 -0
- package/dist/cli/{chunk-tfycddbt.js → chunk-bjk964fp.js} +2 -2
- package/dist/cli/{chunk-gfc5fqvf.js → chunk-br0n8n3e.js} +18 -18
- package/dist/cli/{chunk-gfc5fqvf.js.map → chunk-br0n8n3e.js.map} +1 -1
- package/dist/cli/{chunk-297ajdcv.js → chunk-c69tw29j.js} +6 -6
- package/dist/cli/{chunk-297ajdcv.js.map → chunk-c69tw29j.js.map} +3 -3
- package/dist/cli/chunk-cn3dy3hz.js +146 -0
- package/dist/cli/chunk-cn3dy3hz.js.map +11 -0
- package/dist/cli/{chunk-124fvmzq.js → chunk-dm4mg9bj.js} +11064 -8742
- package/dist/cli/{chunk-124fvmzq.js.map → chunk-dm4mg9bj.js.map} +78 -64
- package/dist/cli/{chunk-dqhg54mr.js → chunk-dmx6cezx.js} +1 -1
- package/dist/cli/{chunk-60hz265r.js → chunk-dpcahcrb.js} +24 -11
- package/dist/cli/chunk-dpcahcrb.js.map +10 -0
- package/dist/cli/{chunk-a57yh0h9.js → chunk-dyk3r7jw.js} +7 -7
- package/dist/cli/{chunk-a57yh0h9.js.map → chunk-dyk3r7jw.js.map} +1 -1
- package/dist/cli/{chunk-twy7psdz.js → chunk-enk76qd5.js} +14 -10
- package/dist/cli/chunk-enk76qd5.js.map +10 -0
- package/dist/cli/{chunk-k3gr1nm9.js → chunk-fqy4n3q2.js} +13 -16
- package/dist/cli/{chunk-k3gr1nm9.js.map → chunk-fqy4n3q2.js.map} +3 -3
- package/dist/cli/{chunk-sc93apfs.js → chunk-frk2wdq1.js} +17 -17
- package/dist/cli/{chunk-sc93apfs.js.map → chunk-frk2wdq1.js.map} +2 -2
- package/dist/cli/{chunk-kdpzw38a.js → chunk-gprwej7h.js} +95 -7
- package/dist/cli/chunk-gprwej7h.js.map +11 -0
- package/dist/cli/chunk-kkrteb15.js +157 -0
- package/dist/cli/chunk-kkrteb15.js.map +10 -0
- package/dist/cli/{chunk-ave1wcbr.js → chunk-m9bp2hc1.js} +1 -1
- package/dist/cli/{chunk-58bt3hag.js → chunk-mrvh4c88.js} +4 -4
- package/dist/cli/{chunk-5cmts6dv.js → chunk-p8zg3a2h.js} +7 -7
- package/dist/cli/{chunk-5cmts6dv.js.map → chunk-p8zg3a2h.js.map} +1 -1
- package/dist/cli/{chunk-0w6hs479.js → chunk-rkqae7kh.js} +30 -18
- package/dist/cli/chunk-rkqae7kh.js.map +10 -0
- package/dist/cli/{chunk-bqxaqn5p.js → chunk-t5xx74rd.js} +8 -8
- package/dist/cli/{chunk-bqxaqn5p.js.map → chunk-t5xx74rd.js.map} +1 -1
- package/dist/cli/{chunk-1f882900.js → chunk-th0pgaj5.js} +2 -2
- package/dist/cli/{chunk-dhwtqnnd.js → chunk-vnbvhgmd.js} +2 -2
- package/dist/cli/{chunk-gxtg6ed2.js → chunk-vzy9rh6y.js} +21 -21
- package/dist/cli/{chunk-gxtg6ed2.js.map → chunk-vzy9rh6y.js.map} +3 -3
- package/dist/cli/{chunk-j1x92mx9.js → chunk-w6e455pz.js} +1 -1
- package/dist/cli/chunk-wehv26ry.js +155 -0
- package/dist/cli/chunk-wehv26ry.js.map +11 -0
- package/dist/cli/{chunk-y4msrwm9.js → chunk-xgq4eytj.js} +15 -15
- package/dist/cli/{chunk-36bxs9c7.js → chunk-xt0qvz1t.js} +27 -23
- package/dist/cli/chunk-xt0qvz1t.js.map +10 -0
- package/dist/cli/index.js +78 -42
- package/dist/cli/index.js.map +7 -6
- package/dist/types/ai/changelog-components.d.ts +18 -0
- package/dist/types/ai/changelog-markdown.d.ts +12 -0
- package/dist/types/ai/openapi-components.d.ts +7 -7
- package/dist/types/ai/operation-details.d.ts +39 -0
- package/dist/types/ai/relative-links.d.ts +3 -1
- package/dist/types/ai/serializers.d.ts +6 -4
- package/dist/types/analytics/head.d.ts +4 -2
- package/dist/types/analytics/script.d.ts +8 -2
- package/dist/types/components/content/youtube.d.ts +20 -0
- package/dist/types/components/layout/nav-utils.d.ts +8 -0
- package/dist/types/components/openapi/example-panels.d.ts +33 -0
- package/dist/types/components/openapi/helpers.d.ts +53 -11
- package/dist/types/components/openapi/snippets.d.ts +7 -1
- package/dist/types/core/alert-diagnostics.d.ts +10 -0
- package/dist/types/core/builtin-tags.d.ts +16 -0
- package/dist/types/core/changelog-list.d.ts +48 -0
- package/dist/types/core/closest-match.d.ts +6 -0
- package/dist/types/core/code-fence-diagnostics.d.ts +18 -0
- package/dist/types/core/code-fences.d.ts +8 -1
- package/dist/types/core/config-input.d.ts +1 -1
- package/dist/types/core/content-assets.d.ts +16 -18
- package/dist/types/core/diagnostics.d.ts +14 -0
- package/dist/types/core/directive-diagnostics.d.ts +22 -8
- package/dist/types/core/former-routes.d.ts +14 -0
- package/dist/types/core/github.d.ts +5 -4
- package/dist/types/core/heading-markers.d.ts +65 -2
- package/dist/types/core/hidden-pages.d.ts +3 -0
- package/dist/types/core/includes.d.ts +23 -0
- package/dist/types/core/last-modified.d.ts +18 -6
- package/dist/types/core/links.d.ts +42 -2
- package/dist/types/core/load-module.d.ts +19 -4
- package/dist/types/core/manifest.d.ts +14 -1
- package/dist/types/core/markdown-mirrors.d.ts +22 -0
- package/dist/types/core/mdx-elements.d.ts +32 -0
- package/dist/types/core/mdx-syntax.d.ts +100 -0
- package/dist/types/core/meta-diagnostics.d.ts +7 -0
- package/dist/types/core/meta.d.ts +32 -5
- package/dist/types/core/nav-diagnostics.d.ts +9 -2
- package/dist/types/core/navigation.d.ts +13 -0
- package/dist/types/core/ordering-prefix.d.ts +6 -0
- package/dist/types/core/pinned-ids.d.ts +23 -0
- package/dist/types/core/project-graph.d.ts +9 -1
- package/dist/types/core/redirect-patterns.d.ts +18 -0
- package/dist/types/core/relative-files.d.ts +31 -0
- package/dist/types/core/schema.d.ts +267 -7
- package/dist/types/core/sources/normalize.d.ts +101 -9
- package/dist/types/core/sources/types.d.ts +16 -0
- package/dist/types/core/static-files.d.ts +10 -0
- package/dist/types/core/static-host.d.ts +42 -0
- package/dist/types/core/svg-images.d.ts +26 -0
- package/dist/types/core/syntax-diagnostics.d.ts +14 -0
- package/dist/types/core/types.d.ts +42 -1
- package/dist/types/deploy/generated-files.d.ts +41 -0
- package/dist/types/deploy/redirects.d.ts +21 -7
- package/dist/types/markdown/code-title.d.ts +9 -5
- package/dist/types/markdown/directives.d.ts +8 -0
- package/dist/types/markdown/fence-language.d.ts +51 -0
- package/dist/types/markdown/fence-meta.d.ts +5 -0
- package/dist/types/markdown/github-alerts.d.ts +35 -0
- package/dist/types/openapi/asyncapi.d.ts +6 -5
- package/dist/types/openapi/checks.d.ts +10 -5
- package/dist/types/openapi/model.d.ts +55 -8
- package/dist/types/openapi/parse.d.ts +4 -1
- package/dist/types/sources/filesystem.d.ts +14 -4
- package/dist/types/sources/mdx-remote.d.ts +6 -3
- package/dist/types/sources/registry.d.ts +3 -3
- package/dist/types/theme/color.d.ts +33 -0
- package/dist/types/theme/palette.d.ts +122 -0
- package/docs/01-quickstart.mdx +1 -1
- package/docs/02-deployment.mdx +23 -8
- package/docs/04-migrating.mdx +16 -4
- package/docs/advanced/changelog.mdx +27 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +1 -1
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +1 -1
- package/docs/cli/index.mdx +4 -2
- package/docs/cli/validate.mdx +10 -7
- package/docs/configuration/analytics.mdx +2 -0
- package/docs/configuration/customization.mdx +3 -1
- package/docs/configuration/index.mdx +2 -2
- package/docs/configuration/theming.mdx +5 -1
- package/docs/content/components.mdx +26 -6
- package/docs/content/frontmatter.mdx +1 -1
- package/docs/content/includes.mdx +6 -2
- package/docs/content/index.mdx +11 -1
- package/docs/content/islands.mdx +2 -0
- package/docs/content/meta.mdx +9 -3
- package/docs/content/navigation.mdx +14 -6
- package/docs/content/sources/obsidian.mdx +1 -1
- package/docs/content/sources/remote-mdx.mdx +3 -1
- package/docs/content/syntax.mdx +76 -8
- package/docs/content/variables.mdx +3 -1
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/json-api.mdx +1 -1
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/open-graph.mdx +1 -1
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/graphql.mdx +2 -0
- package/docs/references/openapi.mdx +45 -7
- package/package.json +4 -4
- package/skills/blume/SKILL.md +2 -2
- package/skills/blume-migrate/SKILL.md +49 -27
- package/skills/blume-migrate/references/docsify.md +262 -0
- package/skills/blume-migrate/references/docus.md +298 -0
- package/skills/blume-migrate/references/docusaurus.md +3 -3
- package/skills/blume-migrate/references/fern.md +327 -0
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/gitbook.md +267 -0
- package/skills/blume-migrate/references/github-wiki.md +259 -0
- package/skills/blume-migrate/references/jekyll.md +253 -0
- package/skills/blume-migrate/references/mdbook.md +256 -0
- package/skills/blume-migrate/references/mintlify.md +5 -5
- package/skills/blume-migrate/references/mkdocs.md +236 -0
- package/skills/blume-migrate/references/monorepo.md +20 -8
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/readme.md +257 -0
- package/skills/blume-migrate/references/redocly.md +198 -0
- package/skills/blume-migrate/references/starlight.md +3 -3
- package/skills/blume-migrate/references/vitepress.md +204 -0
- package/skills/blume-migrate/references/vuepress.md +271 -0
- package/skills/blume-migrate/scripts/docsify-codemod.mjs +2387 -0
- package/skills/blume-migrate/scripts/docus-codemod.mjs +2542 -0
- package/skills/blume-migrate/scripts/fern-codemod.mjs +2633 -0
- package/skills/blume-migrate/scripts/github-wiki-codemod.mjs +2808 -0
- package/skills/blume-migrate/scripts/include-excerpts.mjs +649 -0
- package/skills/blume-migrate/scripts/jekyll-codemod.mjs +3649 -0
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +17 -13
- package/skills/blume-migrate/scripts/mkdocs-codemod.mjs +2526 -0
- package/skills/blume-migrate/scripts/operation-routes.mjs +508 -0
- package/skills/blume-migrate/scripts/pin-heading-ids.mjs +1049 -0
- package/skills/blume-migrate/scripts/readme-codemod.mjs +4139 -0
- package/skills/blume-migrate/scripts/vitepress-codemod.mjs +1511 -0
- package/src/ai/changelog-components.ts +24 -0
- package/src/ai/changelog-markdown.ts +45 -41
- package/src/ai/component-markdown.ts +22 -9
- package/src/ai/llms.ts +36 -5
- package/src/ai/markdown.ts +2 -2
- package/src/ai/openapi-components.ts +25 -9
- package/src/ai/operation-details.ts +208 -0
- package/src/ai/relative-links.ts +48 -8
- package/src/ai/serializers.ts +7 -6
- package/src/ai/site-skill.ts +6 -2
- package/src/analytics/head.ts +11 -5
- package/src/analytics/script.ts +13 -3
- package/src/astro/generate.ts +32 -6
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +27 -1
- package/src/astro/mdx-source-errors.ts +46 -0
- package/src/astro/templates.ts +89 -185
- package/src/audit/checks/redirects.ts +5 -1
- package/src/audit/redirects.ts +36 -19
- package/src/audit/report.ts +22 -9
- package/src/audit/run.ts +12 -28
- package/src/audit/terms.ts +23 -0
- package/src/audit/url.ts +2 -2
- package/src/cli/build-failure.ts +256 -7
- package/src/cli/command-meta.ts +1 -1
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.ts +12 -3
- package/src/cli/commands/check.ts +13 -2
- package/src/cli/commands/dev.ts +1 -1
- package/src/cli/commands/doctor.ts +4 -2
- package/src/cli/commands/init.ts +3 -3
- package/src/cli/commands/preview.ts +17 -1
- package/src/cli/commands/validate.ts +22 -10
- package/src/cli/prepare.ts +1 -1
- package/src/cli/preview-pages.ts +161 -0
- package/src/cli/unknown-flags.ts +1 -42
- package/src/components/code-copy.ts +51 -0
- package/src/components/code-language.ts +75 -0
- package/src/components/content/AccordionItem.astro +16 -1
- package/src/components/content/Callout.astro +11 -1
- package/src/components/content/Changelog.astro +189 -0
- package/src/components/content/CodeBlock.astro +8 -11
- package/src/components/content/Tabs.astro +16 -2
- package/src/components/content/YouTube.astro +6 -4
- package/src/components/content/code-block.ts +33 -0
- package/src/components/content/content-strings.ts +5 -1
- package/src/components/content/inline-markdown.ts +35 -8
- package/src/components/content/youtube.ts +49 -7
- package/src/components/layout/Analytics.astro +5 -1
- package/src/components/layout/NavTree.astro +8 -3
- package/src/components/layout/RootLayout.astro +18 -31
- package/src/components/layout/nav-utils.ts +14 -0
- package/src/components/layout/search/pagefind.ts +2 -1
- package/src/components/openapi/Operation.astro +4 -0
- package/src/components/openapi/PanelTabs.astro +9 -3
- package/src/components/openapi/RequestBody.astro +42 -8
- package/src/components/openapi/RequestPanel.astro +34 -53
- package/src/components/openapi/example-panels.ts +110 -0
- package/src/components/openapi/helpers.ts +195 -20
- package/src/components/openapi/operation-model.ts +63 -26
- package/src/components/openapi/request.ts +13 -0
- package/src/components/openapi/snippets.ts +14 -2
- package/src/core/alert-diagnostics.ts +89 -0
- package/src/core/builtin-tags.ts +76 -0
- package/src/core/changelog-list.ts +87 -0
- package/src/core/closest-match.ts +41 -0
- package/src/core/code-fence-diagnostics.ts +267 -0
- package/src/core/code-fences.ts +43 -7
- package/src/core/component-diagnostics.ts +65 -12
- package/src/core/config-input.ts +1 -1
- package/src/core/config.ts +46 -1
- package/src/core/content-assets.ts +64 -144
- package/src/core/diagnostics.ts +36 -3
- package/src/core/directive-diagnostics.ts +265 -47
- package/src/core/former-routes.ts +46 -0
- package/src/core/git-ignored.ts +53 -0
- package/src/core/github.ts +5 -4
- package/src/core/heading-markers.ts +156 -2
- package/src/core/hidden-pages.ts +64 -0
- package/src/core/includes.ts +181 -41
- package/src/core/last-modified.ts +47 -10
- package/src/core/links.ts +438 -83
- package/src/core/load-module.ts +98 -9
- package/src/core/manifest.ts +12 -9
- package/src/core/markdown-mirrors.ts +52 -0
- package/src/core/mdx-elements.ts +153 -0
- package/src/core/mdx-syntax.ts +377 -0
- package/src/core/meta-diagnostics.ts +134 -0
- package/src/core/meta.ts +154 -55
- package/src/core/nav-diagnostics.ts +16 -4
- package/src/core/navigation.ts +70 -10
- package/src/core/ordering-prefix.ts +22 -2
- package/src/core/pinned-ids.ts +141 -0
- package/src/core/project-graph.ts +221 -29
- package/src/core/redirect-patterns.ts +41 -0
- package/src/core/relative-files.ts +145 -0
- package/src/core/schema.ts +17 -3
- package/src/core/sources/mdx-remote.ts +75 -14
- package/src/core/sources/normalize.ts +885 -179
- package/src/core/sources/notion.ts +5 -4
- package/src/core/sources/obsidian.ts +2 -5
- package/src/core/sources/types.ts +17 -0
- package/src/core/static-files.ts +40 -0
- package/src/core/static-host.ts +125 -0
- package/src/core/svg-images.ts +98 -0
- package/src/core/syntax-diagnostics.ts +491 -0
- package/src/core/types.ts +43 -1
- package/src/deploy/artifacts.ts +2 -28
- package/src/deploy/generated-files.ts +128 -0
- package/src/deploy/platforms/vercel.ts +25 -1
- package/src/deploy/redirects.ts +43 -16
- package/src/deploy/sitemap.ts +2 -1
- package/src/markdown/base-links.ts +87 -6
- package/src/markdown/code-title.ts +29 -13
- package/src/markdown/content-assets.ts +210 -0
- package/src/markdown/directives.ts +69 -5
- package/src/markdown/fence-language.ts +106 -0
- package/src/markdown/fence-meta.ts +42 -0
- package/src/markdown/github-alerts.ts +172 -0
- package/src/markdown/heading-anchors.ts +265 -56
- package/src/markdown/include.ts +30 -3
- package/src/markdown/index.ts +145 -40
- package/src/markdown/prompt-text.ts +95 -0
- package/src/markdown/relative-links.ts +37 -2
- package/src/markdown/route-snapshot.ts +22 -12
- package/src/markdown/svg-fallback.ts +51 -0
- package/src/markdown/title-heading.ts +134 -0
- package/src/migrate/migrate.ts +127 -2
- package/src/og/card.ts +14 -4
- package/src/openapi/asyncapi.ts +14 -6
- package/src/openapi/checks.ts +160 -15
- package/src/openapi/model.ts +172 -33
- package/src/openapi/parse.ts +13 -4
- package/src/openapi/render-mdx.ts +55 -9
- package/src/openapi/source.ts +87 -6
- package/src/registry/eject.ts +0 -1
- package/src/search/documents.ts +10 -2
- package/src/sources/filesystem.ts +28 -3
- package/src/sources/mdx-remote.ts +7 -15
- package/src/theme/color.ts +14 -0
- package/src/theme/entry.ts +22 -1
- package/src/theme/palette.ts +74 -1
- package/dist/cli/chunk-0pmb4tr4.js.map +0 -35
- package/dist/cli/chunk-0w6hs479.js.map +0 -10
- package/dist/cli/chunk-150jk7km.js +0 -52
- package/dist/cli/chunk-150jk7km.js.map +0 -10
- package/dist/cli/chunk-36bxs9c7.js.map +0 -10
- package/dist/cli/chunk-53jqw8z0.js +0 -89
- package/dist/cli/chunk-53jqw8z0.js.map +0 -10
- package/dist/cli/chunk-60hz265r.js.map +0 -10
- package/dist/cli/chunk-desvm72z.js.map +0 -14
- package/dist/cli/chunk-dpy8qdjf.js.map +0 -17
- package/dist/cli/chunk-es8h0v3j.js +0 -441
- package/dist/cli/chunk-es8h0v3j.js.map +0 -11
- package/dist/cli/chunk-kdpzw38a.js.map +0 -11
- package/dist/cli/chunk-nbyvgnnm.js.map +0 -36
- package/dist/cli/chunk-s0bdnc7v.js.map +0 -10
- package/dist/cli/chunk-twy7psdz.js.map +0 -10
- package/dist/cli/chunk-ydp3065p.js +0 -64
- package/dist/cli/chunk-ydp3065p.js.map +0 -10
- /package/dist/cli/{chunk-74wfhv79.js.map → chunk-05f21r8h.js.map} +0 -0
- /package/dist/cli/{chunk-9qzgg6mj.js.map → chunk-1cm0h819.js.map} +0 -0
- /package/dist/cli/{chunk-ms9z66nz.js.map → chunk-4rftmttv.js.map} +0 -0
- /package/dist/cli/{chunk-hvcxng5f.js.map → chunk-7tekknev.js.map} +0 -0
- /package/dist/cli/{chunk-bxwhtvw8.js.map → chunk-ahc5gc9h.js.map} +0 -0
- /package/dist/cli/{chunk-tfycddbt.js.map → chunk-bjk964fp.js.map} +0 -0
- /package/dist/cli/{chunk-dqhg54mr.js.map → chunk-dmx6cezx.js.map} +0 -0
- /package/dist/cli/{chunk-ave1wcbr.js.map → chunk-m9bp2hc1.js.map} +0 -0
- /package/dist/cli/{chunk-58bt3hag.js.map → chunk-mrvh4c88.js.map} +0 -0
- /package/dist/cli/{chunk-1f882900.js.map → chunk-th0pgaj5.js.map} +0 -0
- /package/dist/cli/{chunk-dhwtqnnd.js.map → chunk-vnbvhgmd.js.map} +0 -0
- /package/dist/cli/{chunk-j1x92mx9.js.map → chunk-w6e455pz.js.map} +0 -0
- /package/dist/cli/{chunk-y4msrwm9.js.map → chunk-xgq4eytj.js.map} +0 -0
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
* - parses trailing markers (`[#custom-id]`, `{#custom-id}`, `[!toc]`, `[toc]`
|
|
6
6
|
* — see `core/heading-markers.ts`) and strips them from the rendered text;
|
|
7
7
|
|
|
8
|
-
* -
|
|
9
|
-
*
|
|
8
|
+
* - takes out an empty `<a>` the heading holds as its own anchor (GitBook's
|
|
9
|
+
* `<a href="#x" id="x"></a>`, a wiki's `<a name="x"></a>`), whose `id` or
|
|
10
|
+
* `name` then pins the heading's id — see {@link readContent};
|
|
11
|
+
* - assigns the anchor `id` (the `[#custom-id]` pin, else that anchor's id,
|
|
12
|
+
* else a `github-slugger` slug of the marker-free text, `<Badge>` text left
|
|
13
|
+
* out — see `headingSlug`);
|
|
10
14
|
* - wraps `<h2>`–`<h6>` content in an `<a href="#slug">` so a reader can click
|
|
11
15
|
* the heading to copy, bookmark, or share a link straight to that section
|
|
12
16
|
* (`<h1>` — the page title — is slugged for parity but left unwrapped, and
|
|
@@ -28,23 +32,33 @@
|
|
|
28
32
|
* surfaces as `remarkPluginFrontmatter` so the page template can filter them
|
|
29
33
|
* out of the headings list. `[toc]` headings render with the
|
|
30
34
|
* `blume-toc-only` class (visually hidden, still a live anchor target) so the
|
|
31
|
-
* TOC entry has somewhere to scroll to.
|
|
35
|
+
* TOC entry has somewhere to scroll to. `heading-ids` reads a heading's TOC
|
|
36
|
+
* text from its whole text content, badge included, so a heading holding a
|
|
37
|
+
* `<Badge>` reports its badge-free text under `frontmatter[TOC_TEXT_KEY]`.
|
|
32
38
|
*/
|
|
33
39
|
|
|
34
40
|
import { satteriCollectHastText } from "@astrojs/markdown-satteri";
|
|
35
41
|
import GithubSlugger from "github-slugger";
|
|
36
42
|
|
|
37
43
|
import {
|
|
44
|
+
headingSlug,
|
|
45
|
+
joinHeadingText,
|
|
46
|
+
jsxAnchorTarget,
|
|
38
47
|
occupySlug,
|
|
39
48
|
parseHeadingMarkers,
|
|
49
|
+
rawHeadingTag,
|
|
40
50
|
TOC_HIDDEN_KEY,
|
|
51
|
+
TOC_TEXT_KEY,
|
|
41
52
|
} from "../core/heading-markers.ts";
|
|
53
|
+
import type { JsxAttribute } from "../core/heading-markers.ts";
|
|
42
54
|
|
|
43
55
|
/** A hast property value: an attribute primitive or a token list. */
|
|
44
56
|
type HastPropertyValue = string | number | boolean | (string | number)[];
|
|
45
57
|
|
|
46
58
|
/** A minimal hast node (avoids a hast type dependency). */
|
|
47
59
|
interface HastNode {
|
|
60
|
+
/** An MDX JSX element's attributes. */
|
|
61
|
+
attributes?: JsxAttribute[];
|
|
48
62
|
children?: HastNode[];
|
|
49
63
|
name?: string;
|
|
50
64
|
properties?: Record<string, HastPropertyValue>;
|
|
@@ -83,15 +97,18 @@ const WRAPPED = new Set(["h2", "h3", "h4", "h5", "h6"]);
|
|
|
83
97
|
/** The class that renders a `[toc]`-only heading as an invisible anchor. */
|
|
84
98
|
const TOC_ONLY_CLASS = "blume-toc-only";
|
|
85
99
|
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
/**
|
|
101
|
+
* True for an `<a>`: an element, a JSX element, or (in `.md`, where inline
|
|
102
|
+
* HTML stays raw) a raw opening `<a>` tag.
|
|
103
|
+
*/
|
|
104
|
+
const isAnchor = (node: HastNode): boolean =>
|
|
105
|
+
(node.tagName ?? node.name) === "a" ||
|
|
106
|
+
(node.type === "raw" &&
|
|
107
|
+
rawHeadingTag(node.value ?? "").kind === "anchor-open");
|
|
108
|
+
|
|
109
|
+
/** True if the nodes already contain an `<a>`, so wrapping would nest links. */
|
|
110
|
+
const containsAnchor = (nodes: readonly HastNode[]): boolean =>
|
|
111
|
+
nodes.some((node) => isAnchor(node) || containsAnchor(node.children ?? []));
|
|
95
112
|
|
|
96
113
|
// One state record per document render. The plugin instance is shared across
|
|
97
114
|
// every page, but slug disambiguation (and the hidden-heading list) must reset
|
|
@@ -102,6 +119,11 @@ interface RenderState {
|
|
|
102
119
|
/** Slugs of `[!toc]` headings, shared by reference with the frontmatter. */
|
|
103
120
|
hidden: string[];
|
|
104
121
|
slugger: GithubSlugger;
|
|
122
|
+
/**
|
|
123
|
+
* TOC text by slug for badge-holding headings, shared by reference with the
|
|
124
|
+
* frontmatter once the first one is recorded.
|
|
125
|
+
*/
|
|
126
|
+
tocText?: Record<string, string>;
|
|
105
127
|
}
|
|
106
128
|
|
|
107
129
|
const FALLBACK_SCOPE = {};
|
|
@@ -122,10 +144,30 @@ const stateFor = (ctx: HastContext): RenderState => {
|
|
|
122
144
|
const frontmatter = ctx.data?.astro?.frontmatter;
|
|
123
145
|
if (frontmatter) {
|
|
124
146
|
frontmatter[TOC_HIDDEN_KEY] = state.hidden;
|
|
147
|
+
// The TOC text map is added only by a page with a badge in a heading, so
|
|
148
|
+
// a stale one is dropped rather than replaced.
|
|
149
|
+
Reflect.deleteProperty(frontmatter, TOC_TEXT_KEY);
|
|
125
150
|
}
|
|
126
151
|
return state;
|
|
127
152
|
};
|
|
128
153
|
|
|
154
|
+
/** Record a badge-holding heading's TOC text (see {@link TOC_TEXT_KEY}). */
|
|
155
|
+
const recordTocText = (
|
|
156
|
+
state: RenderState,
|
|
157
|
+
ctx: HastContext,
|
|
158
|
+
slug: string,
|
|
159
|
+
text: string
|
|
160
|
+
): void => {
|
|
161
|
+
if (!state.tocText) {
|
|
162
|
+
state.tocText = {};
|
|
163
|
+
const frontmatter = ctx.data?.astro?.frontmatter;
|
|
164
|
+
if (frontmatter) {
|
|
165
|
+
frontmatter[TOC_TEXT_KEY] = state.tocText;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
state.tocText[slug] = text;
|
|
169
|
+
};
|
|
170
|
+
|
|
129
171
|
/** Whether a heading already carries a usable string `id`. */
|
|
130
172
|
const isStringId = (value: HastPropertyValue | undefined): value is string =>
|
|
131
173
|
typeof value === "string";
|
|
@@ -176,23 +218,147 @@ const stripMarkers = (node: HastNode): StrippedHeading => {
|
|
|
176
218
|
};
|
|
177
219
|
};
|
|
178
220
|
|
|
179
|
-
/**
|
|
180
|
-
|
|
221
|
+
/** A heading's content read for its anchor, past its trailing markers. */
|
|
222
|
+
interface HeadingContent {
|
|
223
|
+
/** The children the heading renders: its own empty anchors taken out. */
|
|
224
|
+
children: HastNode[];
|
|
225
|
+
/** The `id` (else `name`) of an anchor taken out: the heading's id. */
|
|
226
|
+
target?: string;
|
|
227
|
+
/** The heading's text with its badges left out, when it holds one. */
|
|
228
|
+
text?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** An empty JSX `<a>` (an `.mdx` heading's own anchor). */
|
|
232
|
+
const isEmptyJsxAnchor = (node: HastNode): boolean =>
|
|
233
|
+
node.type === "mdxJsxTextElement" &&
|
|
234
|
+
node.name === "a" &&
|
|
235
|
+
(node.children ?? []).length === 0;
|
|
236
|
+
|
|
237
|
+
/** True for a raw `</a>`. */
|
|
238
|
+
const isRawAnchorClose = (node: HastNode | undefined): boolean =>
|
|
239
|
+
node?.type === "raw" &&
|
|
240
|
+
rawHeadingTag(node.value ?? "").kind === "anchor-close";
|
|
241
|
+
|
|
242
|
+
/** A heading child's text content; raw HTML has none. */
|
|
243
|
+
const textPiece = (node: HastNode, ctx: HastContext): string => {
|
|
244
|
+
if (node.type === "text") {
|
|
245
|
+
return node.value ?? "";
|
|
246
|
+
}
|
|
247
|
+
return node.type === "raw" ? "" : ctx.textContent(node);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/** An empty anchor in a heading: how many nodes it spans, and its target. */
|
|
251
|
+
interface OwnAnchor {
|
|
252
|
+
span: number;
|
|
253
|
+
target?: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The empty `<a>` that starts at `children[index]`, if one does: a JSX
|
|
258
|
+
* element with no children, a self-closing raw tag, or a raw tag closed by
|
|
259
|
+
* the next node.
|
|
260
|
+
*/
|
|
261
|
+
const ownAnchorAt = (
|
|
262
|
+
children: readonly HastNode[],
|
|
263
|
+
index: number
|
|
264
|
+
): OwnAnchor | undefined => {
|
|
265
|
+
const child = children[index];
|
|
266
|
+
if (child && isEmptyJsxAnchor(child)) {
|
|
267
|
+
return { span: 1, target: jsxAnchorTarget(child.attributes ?? []) };
|
|
268
|
+
}
|
|
269
|
+
const tag =
|
|
270
|
+
child?.type === "raw" ? rawHeadingTag(child.value ?? "") : undefined;
|
|
271
|
+
if (tag?.kind !== "anchor-open") {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
if (tag.selfClosing) {
|
|
275
|
+
return { span: 1, target: tag.target };
|
|
276
|
+
}
|
|
277
|
+
return isRawAnchorClose(children[index + 1])
|
|
278
|
+
? { span: 2, target: tag.target }
|
|
279
|
+
: undefined;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* How a heading child moves through a badge: undefined for no badge, else
|
|
284
|
+
* the change it makes to the depth of raw `<Badge>` tags its text sits in
|
|
285
|
+
* (a JSX badge holds its text, so it changes nothing).
|
|
286
|
+
*/
|
|
287
|
+
const badgeStep = (child: HastNode): number | undefined => {
|
|
288
|
+
if (child.type === "mdxJsxTextElement" && child.name === "Badge") {
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
291
|
+
const tag =
|
|
292
|
+
child.type === "raw" ? rawHeadingTag(child.value ?? "") : undefined;
|
|
293
|
+
if (tag?.kind !== "badge") {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
if (tag.selfClosing) {
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
return tag.closing ? -1 : 1;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Read a heading's children for its anchor:
|
|
304
|
+
*
|
|
305
|
+
* - An empty `<a>` is the heading's own anchor — an export's
|
|
306
|
+
* `<a href="#x" id="x"></a>`, a wiki's `<a name="x"></a>` — kept beside
|
|
307
|
+
* the heading's text so links to `#x` land there. Left in, it would nest
|
|
308
|
+
* inside the self-link (invalid HTML), or stop the self-link from
|
|
309
|
+
* rendering. It comes out, and its `id` (else `name`) becomes the
|
|
310
|
+
* heading's id, so `#x` keeps working. A heading with no other content
|
|
311
|
+
* keeps it.
|
|
312
|
+
* - A `<Badge>` is a label beside the heading, not part of its name: its text
|
|
313
|
+
* stays out of the heading's id and TOC entry. In `.mdx` it is a JSX
|
|
314
|
+
* element; in `.md`, raw tags around its text.
|
|
315
|
+
*/
|
|
316
|
+
const readContent = (
|
|
317
|
+
children: readonly HastNode[],
|
|
318
|
+
ctx: HastContext
|
|
319
|
+
): HeadingContent => {
|
|
320
|
+
const kept: HastNode[] = [];
|
|
321
|
+
const pieces: (string | null)[] = [];
|
|
322
|
+
let target: string | undefined;
|
|
323
|
+
let badges = false;
|
|
324
|
+
let badgeDepth = 0;
|
|
325
|
+
// Nodes still to skip: the `</a>` of a raw anchor taken out.
|
|
326
|
+
let skip = 0;
|
|
327
|
+
for (const [index, child] of children.entries()) {
|
|
328
|
+
const anchor = skip > 0 ? undefined : ownAnchorAt(children, index);
|
|
329
|
+
if (skip > 0 || anchor) {
|
|
330
|
+
target ??= anchor?.target;
|
|
331
|
+
skip = anchor ? anchor.span - 1 : skip - 1;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
kept.push(child);
|
|
335
|
+
const step = badgeStep(child);
|
|
336
|
+
if (step === undefined) {
|
|
337
|
+
if (badgeDepth === 0) {
|
|
338
|
+
pieces.push(textPiece(child, ctx));
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
badges = true;
|
|
342
|
+
pieces.push(null);
|
|
343
|
+
badgeDepth = Math.max(0, badgeDepth + step);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (kept.length === 0) {
|
|
347
|
+
return { children: [...children] };
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
children: kept,
|
|
351
|
+
target,
|
|
352
|
+
text: badges ? joinHeadingText(pieces) : undefined,
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
/** The heading's marker-free text content, as `heading-ids` reads it. */
|
|
357
|
+
const headingText = (
|
|
181
358
|
node: HastNode,
|
|
182
359
|
ctx: HastContext,
|
|
183
|
-
slugger: GithubSlugger,
|
|
184
360
|
stripped: StrippedHeading
|
|
185
361
|
): string => {
|
|
186
|
-
if (stripped.id !== undefined) {
|
|
187
|
-
// Pinning occupies the id, so a later heading whose auto-slug collides
|
|
188
|
-
// disambiguates (`setup` → `setup-1`) instead of duplicating the anchor.
|
|
189
|
-
occupySlug(slugger, stripped.id);
|
|
190
|
-
return stripped.id;
|
|
191
|
-
}
|
|
192
|
-
const existingId = node.properties?.id;
|
|
193
|
-
if (isStringId(existingId)) {
|
|
194
|
-
return existingId;
|
|
195
|
-
}
|
|
196
362
|
// The marker suffix is a trailing slice of the text content, so the
|
|
197
363
|
// marker-free text is the content minus exactly what the strip removed.
|
|
198
364
|
const fullText = ctx.textContent(node);
|
|
@@ -203,7 +369,7 @@ const slugFor = (
|
|
|
203
369
|
// resolved value; the helper is the same one `heading-ids` defers to.
|
|
204
370
|
// SAFETY: HastNode is a structural subset of the hast element shape the
|
|
205
371
|
// helper walks (children/type/value), so the node always fits.
|
|
206
|
-
|
|
372
|
+
return rawText.includes("frontmatter")
|
|
207
373
|
? satteriCollectHastText(
|
|
208
374
|
{
|
|
209
375
|
...node,
|
|
@@ -212,7 +378,28 @@ const slugFor = (
|
|
|
212
378
|
ctx.data?.astro?.frontmatter ?? {}
|
|
213
379
|
)
|
|
214
380
|
: rawText;
|
|
215
|
-
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
/** The slug for a heading, mirroring Satteri's `heading-ids` exactly. */
|
|
384
|
+
const slugFor = (
|
|
385
|
+
node: HastNode,
|
|
386
|
+
ctx: HastContext,
|
|
387
|
+
slugger: GithubSlugger,
|
|
388
|
+
stripped: StrippedHeading,
|
|
389
|
+
content: HeadingContent
|
|
390
|
+
): string => {
|
|
391
|
+
const pinned = stripped.id ?? content.target;
|
|
392
|
+
if (pinned !== undefined) {
|
|
393
|
+
// Pinning occupies the id, so a later heading whose auto-slug collides
|
|
394
|
+
// disambiguates (`setup` → `setup-1`) instead of duplicating the anchor.
|
|
395
|
+
occupySlug(slugger, pinned);
|
|
396
|
+
return pinned;
|
|
397
|
+
}
|
|
398
|
+
const existingId = node.properties?.id;
|
|
399
|
+
if (isStringId(existingId)) {
|
|
400
|
+
return existingId;
|
|
401
|
+
}
|
|
402
|
+
return headingSlug(slugger, content.text ?? headingText(node, ctx, stripped));
|
|
216
403
|
};
|
|
217
404
|
|
|
218
405
|
/** The heading's class list with `blume-toc-only` appended. */
|
|
@@ -235,6 +422,47 @@ const hasTocOnlyClass = (node: HastNode): boolean => {
|
|
|
235
422
|
: value === TOC_ONLY_CLASS;
|
|
236
423
|
};
|
|
237
424
|
|
|
425
|
+
/**
|
|
426
|
+
* A heading left without its self-link. Marker-free headings mutate in place;
|
|
427
|
+
* a stripped one, one that lost its own anchor, or a `[toc]`-only one needs
|
|
428
|
+
* its children (and class) replaced, so it re-emits as a new element carrying
|
|
429
|
+
* the original children as refs.
|
|
430
|
+
*/
|
|
431
|
+
const unwrappedHeading = (
|
|
432
|
+
node: HastNode,
|
|
433
|
+
ctx: HastContext,
|
|
434
|
+
slug: string,
|
|
435
|
+
stripped: StrippedHeading,
|
|
436
|
+
content: HeadingContent
|
|
437
|
+
): HastNode | undefined => {
|
|
438
|
+
const tocOnly = stripped.toc === "only" || hasTocOnlyClass(node);
|
|
439
|
+
if (
|
|
440
|
+
stripped.strippedLength ||
|
|
441
|
+
content.children.length !== stripped.children.length ||
|
|
442
|
+
(tocOnly && !hasTocOnlyClass(node))
|
|
443
|
+
) {
|
|
444
|
+
const properties = tocOnly
|
|
445
|
+
? {
|
|
446
|
+
...node.properties,
|
|
447
|
+
className: withTocOnlyClass(node.properties?.className),
|
|
448
|
+
id: slug,
|
|
449
|
+
}
|
|
450
|
+
: { ...node.properties, id: slug };
|
|
451
|
+
return {
|
|
452
|
+
children: content.children,
|
|
453
|
+
properties,
|
|
454
|
+
tagName: node.tagName,
|
|
455
|
+
type: "element",
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
// Unwrapped headings (h1, an empty slug, or one that already links) still
|
|
459
|
+
// need the id so `heading-ids` adopts it instead of re-slugging.
|
|
460
|
+
if (!isStringId(node.properties?.id)) {
|
|
461
|
+
ctx.setProperty(node, "id", slug);
|
|
462
|
+
}
|
|
463
|
+
return undefined;
|
|
464
|
+
};
|
|
465
|
+
|
|
238
466
|
/**
|
|
239
467
|
* Build the plugin. Always parses markers and assigns ids; `wrap: false` only
|
|
240
468
|
* disables the self-linking anchor wrap on `<h2>`–`<h6>`.
|
|
@@ -247,50 +475,31 @@ export const headingAnchorPlugin = (
|
|
|
247
475
|
visit(node, ctx) {
|
|
248
476
|
const state = stateFor(ctx);
|
|
249
477
|
const stripped = stripMarkers(node);
|
|
250
|
-
const
|
|
478
|
+
const content = readContent(stripped.children, ctx);
|
|
479
|
+
const slug = slugFor(node, ctx, state.slugger, stripped, content);
|
|
251
480
|
if (stripped.toc === "hide") {
|
|
252
481
|
state.hidden.push(slug);
|
|
253
482
|
}
|
|
254
|
-
|
|
483
|
+
if (content.text !== undefined) {
|
|
484
|
+
recordTocText(state, ctx, slug, content.text.trim());
|
|
485
|
+
}
|
|
255
486
|
const wrap =
|
|
256
487
|
options.wrap !== false &&
|
|
257
488
|
node.tagName !== undefined &&
|
|
258
489
|
WRAPPED.has(node.tagName) &&
|
|
259
490
|
slug !== "" &&
|
|
260
|
-
|
|
261
|
-
!
|
|
491
|
+
stripped.toc !== "only" &&
|
|
492
|
+
!hasTocOnlyClass(node) &&
|
|
493
|
+
!containsAnchor(content.children);
|
|
262
494
|
if (!wrap) {
|
|
263
|
-
|
|
264
|
-
// needs its children (and class) replaced, so it re-emits as a new
|
|
265
|
-
// element carrying the original children as refs.
|
|
266
|
-
if (stripped.strippedLength || (tocOnly && !hasTocOnlyClass(node))) {
|
|
267
|
-
const properties = tocOnly
|
|
268
|
-
? {
|
|
269
|
-
...node.properties,
|
|
270
|
-
className: withTocOnlyClass(node.properties?.className),
|
|
271
|
-
id: slug,
|
|
272
|
-
}
|
|
273
|
-
: { ...node.properties, id: slug };
|
|
274
|
-
return {
|
|
275
|
-
children: stripped.children,
|
|
276
|
-
properties,
|
|
277
|
-
tagName: node.tagName,
|
|
278
|
-
type: "element",
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
// Unwrapped headings (h1, an empty slug, or one that already links)
|
|
282
|
-
// still need the id so `heading-ids` adopts it instead of re-slugging.
|
|
283
|
-
if (!isStringId(node.properties?.id)) {
|
|
284
|
-
ctx.setProperty(node, "id", slug);
|
|
285
|
-
}
|
|
286
|
-
return;
|
|
495
|
+
return unwrappedHeading(node, ctx, slug, stripped, content);
|
|
287
496
|
}
|
|
288
497
|
// Replacing the heading re-emits its original children as refs inside the
|
|
289
498
|
// new anchor (Satteri passes reused nodes through untouched).
|
|
290
499
|
return {
|
|
291
500
|
children: [
|
|
292
501
|
{
|
|
293
|
-
children:
|
|
502
|
+
children: content.children,
|
|
294
503
|
properties: {
|
|
295
504
|
className: ["blume-heading-anchor"],
|
|
296
505
|
href: `#${slug}`,
|
package/src/markdown/include.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
|
|
3
3
|
import { resolve } from "pathe";
|
|
4
|
+
import type { SourceFormat } from "satteri";
|
|
4
5
|
|
|
5
6
|
import type { IncludeStatement } from "../core/includes.ts";
|
|
6
7
|
import {
|
|
@@ -8,7 +9,11 @@ import {
|
|
|
8
9
|
expandIncludeTarget,
|
|
9
10
|
hasIncludeStatements,
|
|
10
11
|
matchIncludeStatement,
|
|
12
|
+
withDefinitions,
|
|
11
13
|
} from "../core/includes.ts";
|
|
14
|
+
import { escapePinnedIds } from "../core/pinned-ids.ts";
|
|
15
|
+
import { linkDefinitions } from "../core/sources/normalize.ts";
|
|
16
|
+
import type { LinkDefinition } from "../core/sources/normalize.ts";
|
|
12
17
|
import { substituteVariables } from "../core/variables.ts";
|
|
13
18
|
import type { ContentVariables } from "../core/variables.ts";
|
|
14
19
|
import type { MdastNode, MdastValue } from "./mdast.ts";
|
|
@@ -68,6 +73,7 @@ interface PositionedNode extends MdastNode {
|
|
|
68
73
|
interface IncludeVisitorContext {
|
|
69
74
|
fileURL: URL | undefined;
|
|
70
75
|
source: string;
|
|
76
|
+
sourceFormat: SourceFormat;
|
|
71
77
|
replaceNode: (node: MdastNode, replacement: { raw: string }) => void;
|
|
72
78
|
textContent: (node: MdastNode) => string;
|
|
73
79
|
report: (report: {
|
|
@@ -125,6 +131,17 @@ export const includePlugin = (options: IncludePluginOptions = {}) => {
|
|
|
125
131
|
? resolve(options.contentRoot)
|
|
126
132
|
: undefined;
|
|
127
133
|
|
|
134
|
+
// The page's link-reference definitions, read once per source: its own
|
|
135
|
+
// and, appended before the parse (see `withIncludedDefinitions`), every
|
|
136
|
+
// partial's.
|
|
137
|
+
let cached: { definitions: LinkDefinition[]; source: string } | undefined;
|
|
138
|
+
const pageDefinitions = (source: string): LinkDefinition[] => {
|
|
139
|
+
if (cached?.source !== source) {
|
|
140
|
+
cached = { definitions: linkDefinitions(source), source };
|
|
141
|
+
}
|
|
142
|
+
return cached.definitions;
|
|
143
|
+
};
|
|
144
|
+
|
|
128
145
|
const splice = async (
|
|
129
146
|
node: MdastNode,
|
|
130
147
|
statement: IncludeStatement,
|
|
@@ -155,9 +172,19 @@ export const includePlugin = (options: IncludePluginOptions = {}) => {
|
|
|
155
172
|
for (const nested of expanded.errors) {
|
|
156
173
|
ctx.report({ message: nested.message, node, severity: "warning" });
|
|
157
174
|
}
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
|
|
175
|
+
// The splice parses on its own, so a reference in it to a definition
|
|
176
|
+
// elsewhere in the page (the page's, or another partial's) is resolved
|
|
177
|
+
// through a copy of that definition. Substituted here, before the
|
|
178
|
+
// spliced text is parsed: in an MDX page it parses as MDX, where
|
|
179
|
+
// `{{name}}` would be a JavaScript expression. Its pinned heading ids
|
|
180
|
+
// are escaped the way the page's own are (see `escapePinnedIds`).
|
|
181
|
+
return escapePinnedIds(
|
|
182
|
+
substituteVariables(
|
|
183
|
+
withDefinitions(expanded.text, pageDefinitions(ctx.source)),
|
|
184
|
+
options.variables
|
|
185
|
+
),
|
|
186
|
+
ctx.sourceFormat
|
|
187
|
+
);
|
|
161
188
|
};
|
|
162
189
|
|
|
163
190
|
/**
|