blume 1.7.2 → 2.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/AGENTS.md +19 -0
- package/CHANGELOG.md +227 -0
- package/README.md +34 -21
- package/dist/cli/chunk-11j0384y.js +148 -0
- package/dist/cli/chunk-11j0384y.js.map +10 -0
- package/dist/cli/{chunk-xhtpx3ff.js → chunk-1w8dp3qb.js} +17 -16
- package/dist/cli/{chunk-xhtpx3ff.js.map → chunk-1w8dp3qb.js.map} +3 -3
- package/dist/cli/chunk-2q1dwty4.js +75 -0
- package/dist/cli/chunk-2q1dwty4.js.map +11 -0
- package/dist/cli/chunk-41za066z.js +122 -0
- package/dist/cli/chunk-41za066z.js.map +11 -0
- package/dist/cli/chunk-5a2z0198.js +133 -0
- package/dist/cli/chunk-5a2z0198.js.map +10 -0
- package/dist/cli/{chunk-9he6crym.js → chunk-6k8vp3ta.js} +25 -13
- package/dist/cli/{chunk-9he6crym.js.map → chunk-6k8vp3ta.js.map} +4 -4
- package/dist/cli/{chunk-mt76t7dj.js → chunk-79njf86q.js} +133 -54
- package/dist/cli/chunk-79njf86q.js.map +11 -0
- package/dist/cli/{chunk-3w7b2vcx.js → chunk-7ez8ny0t.js} +2 -2
- package/dist/cli/{chunk-688e0dde.js → chunk-88cpgt6h.js} +1 -1
- package/dist/cli/chunk-a9kptbw5.js +361 -0
- package/dist/cli/chunk-a9kptbw5.js.map +14 -0
- package/dist/cli/chunk-abh8yjkn.js +31 -0
- package/dist/cli/chunk-abh8yjkn.js.map +10 -0
- package/dist/cli/chunk-b5aj94ah.js +91 -0
- package/dist/cli/chunk-b5aj94ah.js.map +10 -0
- package/dist/cli/{chunk-hs3gbh8p.js → chunk-bctazmbk.js} +9 -5
- package/dist/cli/chunk-bctazmbk.js.map +10 -0
- package/dist/cli/chunk-beat36xx.js +279 -0
- package/dist/cli/chunk-beat36xx.js.map +10 -0
- package/dist/cli/chunk-bnbmcwfb.js +145 -0
- package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
- package/dist/cli/{chunk-9bkjd11x.js → chunk-bw22s759.js} +15 -5
- package/dist/cli/{chunk-9bkjd11x.js.map → chunk-bw22s759.js.map} +4 -4
- package/dist/cli/chunk-by2290sx.js +39 -0
- package/dist/cli/chunk-by2290sx.js.map +10 -0
- package/dist/cli/chunk-d1tadaw7.js +79 -0
- package/dist/cli/chunk-d1tadaw7.js.map +10 -0
- package/dist/cli/{chunk-t3tj0dgr.js → chunk-d80hr03s.js} +24 -19
- package/dist/cli/chunk-d80hr03s.js.map +15 -0
- package/dist/cli/chunk-ernrthtr.js +97 -0
- package/dist/cli/chunk-ernrthtr.js.map +10 -0
- package/dist/cli/chunk-f2972sbt.js +374 -0
- package/dist/cli/chunk-f2972sbt.js.map +10 -0
- package/dist/cli/{chunk-exeeb35e.js → chunk-f7t03s3g.js} +2 -2
- package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
- package/dist/cli/chunk-fa25z98p.js.map +11 -0
- package/dist/cli/{chunk-12dxjqk7.js → chunk-fh5hj5jt.js} +44 -21
- package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
- package/dist/cli/{chunk-8cd8tj54.js → chunk-j8mw0za6.js} +86 -57
- package/dist/cli/chunk-j8mw0za6.js.map +35 -0
- package/dist/cli/chunk-jts8mvcz.js +106 -0
- package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
- package/dist/cli/{chunk-ejjx8znq.js → chunk-mnqj32sj.js} +505 -536
- package/dist/cli/chunk-mnqj32sj.js.map +12 -0
- package/dist/cli/{chunk-196vjxp9.js → chunk-mwt1k8n7.js} +100 -372
- package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
- package/dist/cli/chunk-nk3ts2xk.js +51 -0
- package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
- package/dist/cli/{chunk-n9sra6sy.js → chunk-pat2zzwc.js} +10 -14
- package/dist/cli/{chunk-n9sra6sy.js.map → chunk-pat2zzwc.js.map} +2 -2
- package/dist/cli/chunk-pnnvybbk.js +176 -0
- package/dist/cli/chunk-pnnvybbk.js.map +11 -0
- package/dist/cli/{chunk-cvky9gb2.js → chunk-sqn5t4q0.js} +81 -87
- package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
- package/dist/cli/{chunk-eevwt1sc.js → chunk-tzne8qfq.js} +15 -15
- package/dist/cli/{chunk-eevwt1sc.js.map → chunk-tzne8qfq.js.map} +1 -1
- package/dist/cli/chunk-xaz13gwg.js +12449 -0
- package/dist/cli/chunk-xaz13gwg.js.map +182 -0
- package/dist/cli/chunk-y3e45rc8.js +102 -0
- package/dist/cli/chunk-y3e45rc8.js.map +10 -0
- package/dist/cli/chunk-z01ze5c1.js +261 -0
- package/dist/cli/chunk-z01ze5c1.js.map +10 -0
- package/dist/cli/{chunk-5n7t497w.js → chunk-z1f5arsg.js} +247 -755
- package/dist/cli/chunk-z1f5arsg.js.map +36 -0
- package/dist/cli/{chunk-hdm2dkd2.js → chunk-zg2gtj10.js} +1086 -2596
- package/dist/cli/chunk-zg2gtj10.js.map +35 -0
- package/dist/cli/{chunk-ppfvdcd4.js → chunk-zxccj738.js} +1 -1
- package/dist/cli/index.js +214 -57
- package/dist/cli/index.js.map +8 -7
- package/dist/types/ai/agent-readability.d.ts +52 -0
- package/dist/types/ai/ai-catalog.d.ts +42 -0
- package/dist/types/ai/api/paths.d.ts +17 -0
- package/dist/types/ai/api-catalog.d.ts +18 -0
- package/dist/types/ai/ask.d.ts +368 -0
- package/dist/types/ai/changelog-markdown.d.ts +2 -0
- package/dist/types/ai/component-markdown.d.ts +2 -2
- package/dist/types/ai/index.d.ts +24 -0
- package/dist/types/ai/link-headers.d.ts +24 -0
- package/dist/types/ai/llms.d.ts +25 -0
- package/dist/types/ai/markdown.d.ts +45 -0
- package/dist/types/ai/mcp/discovery.d.ts +68 -0
- package/dist/types/ai/mcp/tools.d.ts +16 -0
- package/dist/types/ai/openapi-components.d.ts +43 -0
- package/dist/types/ai/relative-links.d.ts +26 -0
- package/dist/types/ai/serializers.d.ts +15 -0
- package/dist/types/ai/skills.d.ts +42 -0
- package/dist/types/ai/tar.d.ts +25 -0
- package/dist/types/ai/visibility.d.ts +17 -0
- package/dist/types/ai/web-bot-auth.d.ts +16 -0
- package/dist/types/analytics/adobe.d.ts +35 -0
- package/dist/types/analytics/amplitude.d.ts +50 -0
- package/dist/types/analytics/clarity.d.ts +31 -0
- package/dist/types/analytics/clearbit.d.ts +29 -0
- package/dist/types/analytics/cloudflare.d.ts +41 -0
- package/dist/types/analytics/fathom.d.ts +41 -0
- package/dist/types/analytics/google-analytics.d.ts +44 -0
- package/dist/types/analytics/google-tag-manager.d.ts +40 -0
- package/dist/types/analytics/head.d.ts +30 -0
- package/dist/types/analytics/heap.d.ts +40 -0
- package/dist/types/analytics/hightouch.d.ts +44 -0
- package/dist/types/analytics/hotjar.d.ts +33 -0
- package/dist/types/analytics/index.d.ts +61 -0
- package/dist/types/analytics/inline.d.ts +17 -0
- package/dist/types/analytics/logrocket.d.ts +44 -0
- package/dist/types/analytics/mixpanel.d.ts +67 -0
- package/dist/types/analytics/pirsch.d.ts +42 -0
- package/dist/types/analytics/plausible.d.ts +56 -0
- package/dist/types/analytics/posthog.d.ts +45 -0
- package/dist/types/analytics/schema.d.ts +320 -0
- package/dist/types/analytics/script.d.ts +46 -0
- package/dist/types/analytics/segment.d.ts +50 -0
- package/dist/types/analytics/vercel.d.ts +48 -0
- package/dist/types/astro/integration.d.ts +76 -0
- package/dist/types/astro/markdown-negotiation.d.ts +23 -0
- package/dist/types/astro/module-types.d.ts +14 -0
- package/dist/types/astro/pages.d.ts +44 -0
- package/dist/types/cli/env.d.ts +12 -0
- package/dist/types/cli/init/scaffold.d.ts +154 -0
- package/dist/types/components/layout/nav-utils.d.ts +11 -0
- package/dist/types/core/adapter.d.ts +47 -0
- package/dist/types/core/api-name.d.ts +7 -0
- package/dist/types/core/changelog-index.d.ts +13 -0
- package/dist/types/core/config-input.d.ts +209 -505
- package/dist/types/core/config.d.ts +60 -34
- package/dist/types/core/content-assets.d.ts +76 -0
- package/dist/types/core/custom-pages.d.ts +33 -0
- package/dist/types/core/data.d.ts +28 -11
- package/dist/types/core/define-components.d.ts +12 -9
- package/dist/types/core/deployment-env.d.ts +6 -11
- package/dist/types/core/frontmatter.d.ts +10 -0
- package/dist/types/core/graph.d.ts +18 -0
- package/dist/types/core/heading-markers.d.ts +54 -0
- package/dist/types/core/i18n-ui.d.ts +6 -2
- package/dist/types/core/i18n.d.ts +87 -0
- package/dist/types/core/includes.d.ts +138 -0
- package/dist/types/core/last-modified.d.ts +47 -0
- package/dist/types/core/links.d.ts +95 -0
- package/dist/types/core/locale-links.d.ts +60 -0
- package/dist/types/core/manifest.d.ts +17 -0
- package/dist/types/core/meta.d.ts +38 -0
- package/dist/types/core/nav-diagnostics.d.ts +26 -0
- package/dist/types/core/navigation.d.ts +6 -0
- package/dist/types/core/node-require.d.ts +19 -0
- package/dist/types/core/package-json.d.ts +13 -0
- package/dist/types/core/probe.d.ts +42 -0
- package/dist/types/core/project-graph.d.ts +51 -0
- package/dist/types/core/project.d.ts +2 -0
- package/dist/types/core/safe-href.d.ts +2 -0
- package/dist/types/core/safe-links.d.ts +26 -0
- package/dist/types/core/schema.d.ts +2291 -441
- package/dist/types/core/site-url.d.ts +16 -0
- package/dist/types/core/sources/assets.d.ts +36 -0
- package/dist/types/core/sources/cache.d.ts +37 -0
- package/dist/types/core/sources/collection.d.ts +28 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
- package/dist/types/core/sources/contentful.d.ts +40 -0
- package/dist/types/core/sources/filesystem.d.ts +24 -0
- package/dist/types/core/sources/github-releases.d.ts +31 -0
- package/dist/types/core/sources/json.d.ts +30 -0
- package/dist/types/core/sources/lexical.d.ts +19 -0
- package/dist/types/core/sources/lower.d.ts +75 -0
- package/dist/types/core/sources/mdx-remote.d.ts +28 -0
- package/dist/types/core/sources/normalize.d.ts +147 -0
- package/dist/types/core/sources/notion.d.ts +131 -0
- package/dist/types/core/sources/obsidian.d.ts +46 -0
- package/dist/types/core/sources/payload.d.ts +39 -0
- package/dist/types/core/sources/portable-text.d.ts +42 -0
- package/dist/types/core/sources/read.d.ts +23 -0
- package/dist/types/core/sources/remote.d.ts +74 -0
- package/dist/types/core/sources/resolve.d.ts +19 -0
- package/dist/types/core/sources/sanity.d.ts +43 -0
- package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
- package/dist/types/core/sources/strapi.d.ts +33 -0
- package/dist/types/core/sources/types.d.ts +7 -0
- package/dist/types/core/sources/watch.d.ts +45 -0
- package/dist/types/core/text-width.d.ts +11 -0
- package/dist/types/core/types.d.ts +20 -1
- package/dist/types/core/unrecognized-keys.d.ts +7 -0
- package/dist/types/core/versions.d.ts +72 -0
- package/dist/types/core/yaml.d.ts +9 -0
- package/dist/types/deploy/adapter-output.d.ts +45 -0
- package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
- package/dist/types/deploy/adapters/index.d.ts +29 -0
- package/dist/types/deploy/adapters/netlify.d.ts +37 -0
- package/dist/types/deploy/adapters/node.d.ts +37 -0
- package/dist/types/deploy/adapters/registry.d.ts +133 -0
- package/dist/types/deploy/adapters/types.d.ts +71 -0
- package/dist/types/deploy/adapters/vercel.d.ts +38 -0
- package/dist/types/deploy/artifacts.d.ts +65 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
- package/dist/types/deploy/function-bundle.d.ts +80 -0
- package/dist/types/deploy/headers.d.ts +50 -0
- package/dist/types/deploy/node-headers.d.ts +42 -0
- package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
- package/dist/types/deploy/platforms/index.d.ts +18 -0
- package/dist/types/deploy/platforms/netlify.d.ts +13 -0
- package/dist/types/deploy/platforms/node.d.ts +11 -0
- package/dist/types/deploy/platforms/paths.d.ts +27 -0
- package/dist/types/deploy/platforms/static.d.ts +10 -0
- package/dist/types/deploy/platforms/types.d.ts +104 -0
- package/dist/types/deploy/platforms/vercel.d.ts +32 -0
- package/dist/types/deploy/redirects.d.ts +53 -0
- package/dist/types/deploy/robots.d.ts +8 -0
- package/dist/types/deploy/rss.d.ts +31 -0
- package/dist/types/deploy/sitemap.d.ts +21 -0
- package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
- package/dist/types/markdown/code-title.d.ts +32 -0
- package/dist/types/markdown/fence-meta.d.ts +23 -0
- package/dist/types/markdown/themes.d.ts +3 -3
- package/dist/types/openapi/asyncapi.d.ts +129 -0
- package/dist/types/openapi/graphql-build.d.ts +8 -0
- package/dist/types/openapi/graphql.d.ts +122 -0
- package/dist/types/openapi/model.d.ts +158 -0
- package/dist/types/openapi/parse.d.ts +57 -0
- package/dist/types/openapi/references.d.ts +37 -25
- package/dist/types/openapi/render-mdx.d.ts +33 -0
- package/dist/types/openapi/sentence.d.ts +7 -0
- package/dist/types/openapi/signature.d.ts +10 -0
- package/dist/types/openapi/source.d.ts +22 -0
- package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
- package/dist/types/reference/asyncapi.d.ts +166 -0
- package/dist/types/reference/graphql.d.ts +181 -0
- package/dist/types/reference/index.d.ts +32 -0
- package/dist/types/reference/openapi.d.ts +165 -0
- package/dist/types/reference/options.d.ts +157 -0
- package/dist/types/reference/scalar.d.ts +136 -0
- package/dist/types/reference/schema.d.ts +630 -0
- package/dist/types/search/adapters/algolia.d.ts +32 -0
- package/dist/types/search/adapters/flexsearch.d.ts +12 -0
- package/dist/types/search/adapters/index.d.ts +31 -0
- package/dist/types/search/adapters/mixedbread.d.ts +22 -0
- package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
- package/dist/types/search/adapters/orama.d.ts +13 -0
- package/dist/types/search/adapters/pagefind.d.ts +12 -0
- package/dist/types/search/adapters/registry.d.ts +228 -0
- package/dist/types/search/adapters/types.d.ts +34 -0
- package/dist/types/search/adapters/typesense.d.ts +42 -0
- package/dist/types/search/build.d.ts +23 -0
- package/dist/types/search/documents.d.ts +90 -0
- package/dist/types/search/facets.d.ts +3 -0
- package/dist/types/search/sync/algolia.d.ts +14 -0
- package/dist/types/search/sync/index.d.ts +14 -0
- package/dist/types/search/sync/orama-cloud.d.ts +10 -0
- package/dist/types/search/sync/typesense.d.ts +14 -0
- package/dist/types/sources/contentful.d.ts +68 -0
- package/dist/types/sources/custom.d.ts +20 -0
- package/dist/types/sources/filesystem.d.ts +42 -0
- package/dist/types/sources/github-releases.d.ts +46 -0
- package/dist/types/sources/index.d.ts +48 -0
- package/dist/types/sources/mdx-remote.d.ts +63 -0
- package/dist/types/sources/notion.d.ts +65 -0
- package/dist/types/sources/obsidian.d.ts +34 -0
- package/dist/types/sources/payload.d.ts +68 -0
- package/dist/types/sources/registry.d.ts +1414 -0
- package/dist/types/sources/sanity.d.ts +69 -0
- package/dist/types/sources/shared.d.ts +46 -0
- package/dist/types/sources/strapi.d.ts +66 -0
- package/dist/types/theme/icon-kind.d.ts +11 -0
- package/dist/types/theme/icons.d.ts +20 -0
- package/docs/01-quickstart.mdx +18 -18
- package/docs/02-deployment.mdx +50 -26
- package/docs/03-upgrading.mdx +351 -0
- package/docs/04-migrating.mdx +58 -0
- package/docs/08-faq.mdx +3 -3
- package/docs/advanced/blog.mdx +13 -6
- package/docs/advanced/changelog.mdx +23 -35
- package/docs/advanced/custom-pages.mdx +20 -8
- package/docs/advanced/meta.ts +1 -8
- package/docs/advanced/skills.mdx +8 -0
- package/docs/cli/audit.mdx +646 -0
- package/docs/cli/doctor.mdx +29 -0
- package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
- package/docs/cli/index.mdx +105 -0
- package/docs/cli/meta.ts +7 -0
- package/docs/{reference → cli}/translate.mdx +1 -1
- package/docs/cli/validate.mdx +41 -0
- package/docs/cli/version.mdx +40 -0
- package/docs/configuration/analytics.mdx +350 -59
- package/docs/configuration/ask-ai.mdx +176 -61
- package/docs/configuration/customization.mdx +15 -9
- package/docs/configuration/index.mdx +52 -31
- package/docs/configuration/search.mdx +75 -54
- package/docs/configuration/theming.mdx +24 -15
- package/docs/content/components.mdx +21 -5
- package/docs/{reference → content}/frontmatter.mdx +37 -1
- package/docs/content/i18n.mdx +8 -6
- package/docs/content/includes.mdx +2 -4
- package/docs/content/index.mdx +1 -1
- package/docs/content/islands.mdx +10 -5
- package/docs/content/meta.mdx +1 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +12 -7
- package/docs/content/sources.mdx +145 -50
- package/docs/content/syntax.mdx +26 -12
- package/docs/content/versioning.mdx +3 -3
- package/docs/discoverability/agent-discovery.mdx +91 -10
- package/docs/discoverability/index.mdx +5 -5
- package/docs/discoverability/json-api.mdx +4 -4
- package/docs/discoverability/llms-txt.mdx +6 -6
- package/docs/discoverability/markdown.mdx +4 -4
- package/docs/discoverability/mcp.mdx +11 -11
- package/docs/discoverability/sitemap-and-robots.mdx +3 -3
- package/docs/index.mdx +2 -2
- package/docs/references/asyncapi.mdx +59 -0
- package/docs/{advanced → references}/graphql.mdx +45 -32
- package/docs/{reference → references}/meta.ts +2 -2
- package/docs/references/openapi.mdx +171 -0
- package/docs/references/scalar.mdx +64 -0
- package/package.json +42 -8
- package/skills/blume/SKILL.md +21 -8
- package/skills/blume-migrate/SKILL.md +22 -21
- package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
- package/skills/blume-migrate/references/docusaurus.md +5 -4
- package/skills/blume-migrate/references/fumadocs.md +4 -4
- package/skills/blume-migrate/references/mintlify.md +23 -8
- package/skills/blume-migrate/references/monorepo.md +6 -6
- package/skills/blume-migrate/references/starlight.md +4 -4
- package/src/ai/agent-readability.ts +26 -22
- package/src/ai/ai-catalog.ts +259 -0
- package/src/ai/api/handlers.ts +46 -11
- package/src/ai/api-catalog.ts +8 -8
- package/src/ai/ask-data.ts +1 -1
- package/src/ai/ask.ts +624 -100
- package/src/ai/changelog-markdown.ts +91 -0
- package/src/ai/component-markdown.ts +328 -12
- package/src/ai/index.ts +45 -0
- package/src/ai/link-headers.ts +19 -6
- package/src/ai/llms.ts +26 -15
- package/src/ai/markdown.ts +35 -5
- package/src/ai/mcp/data.ts +9 -5
- package/src/ai/mcp/discovery.ts +1 -1
- package/src/ai/openapi-components.ts +4 -1
- package/src/ai/relative-links.ts +170 -0
- package/src/ai/serializers.ts +2 -2
- package/src/ai/skills.ts +1 -1
- package/src/ai/web-bot-auth.ts +2 -2
- package/src/analytics/adobe.ts +46 -0
- package/src/analytics/amplitude.ts +79 -0
- package/src/analytics/clarity.ts +46 -0
- package/src/analytics/clearbit.ts +47 -0
- package/src/analytics/cloudflare.ts +67 -0
- package/src/analytics/fathom.ts +64 -0
- package/src/analytics/google-analytics.ts +84 -0
- package/src/analytics/google-tag-manager.ts +61 -0
- package/src/analytics/head.ts +130 -0
- package/src/analytics/heap.ts +65 -0
- package/src/analytics/hightouch.ts +77 -0
- package/src/analytics/hotjar.ts +47 -0
- package/src/analytics/index.ts +71 -0
- package/src/analytics/inline.ts +21 -0
- package/src/analytics/logrocket.ts +71 -0
- package/src/analytics/mixpanel.ts +92 -0
- package/src/analytics/pirsch.ts +66 -0
- package/src/analytics/plausible.ts +83 -0
- package/src/analytics/posthog.ts +78 -0
- package/src/analytics/schema.ts +60 -0
- package/src/analytics/script.ts +60 -0
- package/src/analytics/segment.ts +85 -0
- package/src/analytics/vercel.ts +50 -0
- package/src/astro/adapter-root.ts +7 -9
- package/src/astro/component-slots.ts +131 -91
- package/src/astro/generate.ts +114 -345
- package/src/astro/integration.ts +2 -6
- package/src/astro/pages.ts +13 -101
- package/src/astro/render-deps.ts +379 -0
- package/src/astro/runtime-deps.ts +201 -0
- package/src/astro/templates.ts +554 -541
- package/src/audit/agent.ts +24 -0
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +2 -2
- package/src/audit/checks/dns-aid.ts +1 -1
- package/src/audit/checks/duplicates.ts +3 -1
- package/src/audit/checks/i18n.ts +1 -1
- package/src/audit/checks/indexability.ts +7 -7
- package/src/audit/checks/links.ts +2 -2
- package/src/audit/checks/llms.ts +6 -6
- package/src/audit/checks/network.ts +3 -3
- package/src/audit/checks/og-image.ts +2 -2
- package/src/audit/checks/robots.ts +1 -1
- package/src/audit/checks/sitemap.ts +2 -2
- package/src/audit/checks/social.ts +1 -1
- package/src/audit/run.ts +4 -3
- package/src/audit/terms.ts +31 -0
- package/src/audit/url.ts +13 -13
- package/src/cli/command-meta.ts +10 -0
- package/src/cli/commands/audit.ts +39 -20
- package/src/cli/commands/build.ts +71 -314
- package/src/cli/commands/check.ts +1 -0
- package/src/cli/commands/dev.ts +40 -1
- package/src/cli/commands/doctor.ts +90 -14
- package/src/cli/commands/eject.ts +44 -7
- package/src/cli/commands/eval.ts +2 -2
- package/src/cli/commands/init.ts +161 -41
- package/src/cli/commands/migrate.ts +121 -0
- package/src/cli/commands/preview.ts +7 -1
- package/src/cli/commands/translate.ts +2 -2
- package/src/cli/commands/upgrade.ts +141 -0
- package/src/cli/commands/version.ts +57 -44
- package/src/cli/eject-scripts.ts +121 -6
- package/src/cli/index.ts +11 -1
- package/src/cli/init/install.ts +70 -0
- package/src/cli/init/questions.ts +7 -0
- package/src/cli/init/scaffold.ts +459 -75
- package/src/cli/lazy-command.ts +37 -1
- package/src/cli/prepare.ts +40 -6
- package/src/cli/required-secrets.ts +38 -11
- package/src/cli/unknown-flags.ts +266 -0
- package/src/cli/yarn-pnp.ts +52 -0
- package/src/components/content/AccordionItem.astro +7 -1
- package/src/components/content/Card.astro +4 -3
- package/src/components/content/ColorItem.astro +22 -4
- package/src/components/content/GithubInfo.astro +2 -2
- package/src/components/content/Prompt.astro +25 -25
- package/src/components/content/Tabs.astro +3 -1
- package/src/components/content/Tile.astro +2 -3
- package/src/components/content/Tooltip.astro +57 -9
- package/src/components/content/content-strings.ts +34 -0
- package/src/components/content/diff.ts +1 -1
- package/src/components/content/mermaid-element.ts +13 -2
- package/src/components/content/prompt-markdown.ts +292 -0
- package/src/components/content/tooltip-id.ts +41 -0
- package/src/components/islands/hooks.ts +75 -3
- package/src/components/layout/Analytics.astro +21 -79
- package/src/components/layout/Banner.astro +3 -1
- package/src/components/layout/DiscoveryLinks.astro +69 -0
- package/src/components/layout/Header.astro +83 -20
- package/src/components/layout/LanguageSwitcher.astro +4 -1
- package/src/components/layout/Logo.astro +23 -2
- package/src/components/layout/NavSelector.astro +13 -2
- package/src/components/layout/NavTree.astro +12 -3
- package/src/components/layout/NavTreeScript.astro +17 -3
- package/src/components/layout/PageActions.astro +3 -3
- package/src/components/layout/PageFeedback.astro +11 -1
- package/src/components/layout/PageLayout.astro +52 -5
- package/src/components/layout/ReferenceLayout.astro +21 -12
- package/src/components/layout/RootLayout.astro +69 -43
- package/src/components/layout/Search.astro +30 -6
- package/src/components/layout/WebMcp.astro +1 -1
- package/src/components/layout/analytics-client.ts +101 -15
- package/src/components/layout/drawer-inert.ts +113 -15
- package/src/components/layout/dropdown-clamp.ts +105 -0
- package/src/components/layout/head-scripts.ts +15 -6
- package/src/components/layout/nav-utils.ts +17 -0
- package/src/components/layout/search/algolia.ts +8 -8
- package/src/components/layout/search/orama-cloud.ts +9 -7
- package/src/components/layout/search/typesense.ts +11 -17
- package/src/components/openapi/MessageComposer.astro +2 -2
- package/src/components/openapi/Playground.astro +2 -2
- package/src/components/openapi/playground-client.ts +79 -10
- package/src/core/changelog-index.ts +24 -0
- package/src/core/component-overrides.ts +399 -154
- package/src/core/config-input.ts +212 -543
- package/src/core/config.ts +130 -41
- package/src/core/custom-pages.ts +105 -0
- package/src/core/data.ts +32 -11
- package/src/core/define-components.ts +12 -9
- package/src/core/deployment-env.ts +18 -74
- package/src/core/diagnostics.ts +14 -7
- package/src/core/graph.ts +69 -25
- package/src/core/i18n-ui.ts +6 -2
- package/src/core/i18n.ts +17 -0
- package/src/core/includes.ts +156 -38
- package/src/core/last-modified.ts +6 -11
- package/src/core/links.ts +166 -2
- package/src/core/manifest.ts +10 -3
- package/src/core/navigation.ts +137 -19
- package/src/core/new-tab.ts +35 -0
- package/src/core/node-require.ts +21 -0
- package/src/core/project-graph.ts +42 -26
- package/src/core/project.ts +9 -4
- package/src/core/request-body.ts +61 -0
- package/src/core/safe-href.ts +28 -0
- package/src/core/safe-links.ts +68 -0
- package/src/core/schema.ts +531 -721
- package/src/core/server-features.ts +8 -9
- package/src/core/sources/assets.ts +47 -11
- package/src/core/sources/collection.ts +67 -0
- package/src/core/sources/contentful-rich-text.ts +285 -0
- package/src/core/sources/contentful.ts +173 -0
- package/src/core/sources/github-releases.ts +51 -1
- package/src/core/sources/json.ts +71 -0
- package/src/core/sources/lexical.ts +195 -0
- package/src/core/sources/lower.ts +226 -0
- package/src/core/sources/normalize.ts +52 -2
- package/src/core/sources/notion.ts +39 -28
- package/src/core/sources/payload.ts +135 -0
- package/src/core/sources/portable-text.ts +11 -16
- package/src/core/sources/remote.ts +226 -0
- package/src/core/sources/resolve.ts +104 -166
- package/src/core/sources/sanity.ts +16 -49
- package/src/core/sources/strapi-blocks.ts +124 -0
- package/src/core/sources/strapi.ts +191 -0
- package/src/core/sources/types.ts +12 -1
- package/src/core/types.ts +20 -1
- package/src/core/ui-packs/ar.ts +6 -2
- package/src/core/ui-packs/bg.ts +6 -2
- package/src/core/ui-packs/bn.ts +6 -2
- package/src/core/ui-packs/ca.ts +3 -1
- package/src/core/ui-packs/cs.ts +6 -2
- package/src/core/ui-packs/da.ts +6 -2
- package/src/core/ui-packs/de.ts +6 -2
- package/src/core/ui-packs/el.ts +3 -1
- package/src/core/ui-packs/es.ts +3 -1
- package/src/core/ui-packs/fa.ts +6 -2
- package/src/core/ui-packs/fi.ts +6 -2
- package/src/core/ui-packs/fr.ts +3 -1
- package/src/core/ui-packs/he.ts +6 -2
- package/src/core/ui-packs/hi.ts +6 -2
- package/src/core/ui-packs/hr.ts +6 -2
- package/src/core/ui-packs/hu.ts +6 -2
- package/src/core/ui-packs/id.ts +6 -2
- package/src/core/ui-packs/it.ts +3 -1
- package/src/core/ui-packs/ja.ts +3 -1
- package/src/core/ui-packs/ko.ts +3 -1
- package/src/core/ui-packs/nl.ts +6 -2
- package/src/core/ui-packs/no.ts +6 -2
- package/src/core/ui-packs/pl.ts +6 -2
- package/src/core/ui-packs/pt-br.ts +3 -1
- package/src/core/ui-packs/pt.ts +3 -1
- package/src/core/ui-packs/ro.ts +6 -2
- package/src/core/ui-packs/ru.ts +6 -2
- package/src/core/ui-packs/sk.ts +6 -2
- package/src/core/ui-packs/sr.ts +6 -2
- package/src/core/ui-packs/sv.ts +6 -2
- package/src/core/ui-packs/th.ts +3 -1
- package/src/core/ui-packs/tr.ts +6 -2
- package/src/core/ui-packs/uk.ts +6 -2
- package/src/core/ui-packs/vi.ts +3 -1
- package/src/core/ui-packs/zh-tw.ts +3 -1
- package/src/core/ui-packs/zh.ts +3 -1
- package/src/core/unrecognized-keys.ts +10 -0
- package/src/core/version-cut.ts +116 -8
- package/src/deploy/adapter-output.ts +57 -97
- package/src/deploy/adapters/cloudflare.ts +39 -0
- package/src/deploy/adapters/index.ts +41 -0
- package/src/deploy/adapters/netlify.ts +34 -0
- package/src/deploy/adapters/node.ts +34 -0
- package/src/deploy/adapters/registry.ts +127 -0
- package/src/deploy/adapters/types.ts +92 -0
- package/src/deploy/adapters/vercel.ts +35 -0
- package/src/deploy/artifacts.ts +67 -28
- package/src/deploy/cloudflare-negotiation.ts +179 -100
- package/src/deploy/function-bundle.ts +18 -3
- package/src/deploy/headers.ts +129 -22
- package/src/deploy/node-headers.ts +198 -0
- package/src/deploy/platforms/cloudflare.ts +312 -0
- package/src/deploy/platforms/index.ts +67 -0
- package/src/deploy/platforms/netlify.ts +52 -0
- package/src/deploy/platforms/node.ts +40 -0
- package/src/deploy/platforms/paths.ts +42 -0
- package/src/deploy/platforms/static.ts +29 -0
- package/src/deploy/platforms/types.ts +112 -0
- package/src/deploy/platforms/vercel.ts +193 -0
- package/src/deploy/redirects.ts +30 -18
- package/src/deploy/robots.ts +3 -3
- package/src/deploy/rss.ts +2 -2
- package/src/deploy/sitemap.ts +2 -2
- package/src/deploy/vercel-negotiation.ts +27 -4
- package/src/eval/agents.ts +32 -1
- package/src/eval/findings.ts +19 -11
- package/src/eval/report.ts +10 -2
- package/src/markdown/external-links.ts +65 -0
- package/src/markdown/include.ts +45 -27
- package/src/markdown/index.ts +34 -9
- package/src/markdown/inline-code.ts +12 -6
- package/src/markdown/relative-links.ts +324 -0
- package/src/markdown/themes.ts +3 -3
- package/src/migrate/migrate.ts +149 -0
- package/src/openapi/parse.ts +64 -16
- package/src/openapi/proxy.ts +62 -10
- package/src/openapi/references.ts +147 -147
- package/src/openapi/render-mdx.ts +32 -10
- package/src/openapi/scalar.ts +15 -13
- package/src/openapi/sentence.ts +14 -0
- package/src/openapi/source.ts +37 -21
- package/src/openapi/spec-dependency-error.ts +15 -0
- package/src/reference/asyncapi.ts +83 -0
- package/src/reference/graphql.ts +89 -0
- package/src/reference/index.ts +40 -0
- package/src/reference/openapi.ts +83 -0
- package/src/reference/options.ts +201 -0
- package/src/reference/scalar.ts +136 -0
- package/src/reference/schema.ts +88 -0
- package/src/registry/eject.ts +97 -42
- package/src/search/adapters/algolia.ts +46 -0
- package/src/search/adapters/flexsearch.ts +29 -0
- package/src/search/adapters/index.ts +39 -0
- package/src/search/adapters/mixedbread.ts +39 -0
- package/src/search/adapters/orama-cloud.ts +51 -0
- package/src/search/adapters/orama.ts +24 -0
- package/src/search/adapters/pagefind.ts +27 -0
- package/src/search/adapters/registry.ts +131 -0
- package/src/search/adapters/types.ts +46 -0
- package/src/search/adapters/typesense.ts +57 -0
- package/src/search/build.ts +33 -7
- package/src/search/documents.ts +6 -0
- package/src/search/sync/algolia.ts +12 -11
- package/src/search/sync/index.ts +35 -20
- package/src/search/sync/orama-cloud.ts +12 -9
- package/src/search/sync/typesense.ts +15 -13
- package/src/sources/contentful.ts +63 -0
- package/src/sources/custom.ts +38 -0
- package/src/sources/filesystem.ts +51 -0
- package/src/sources/github-releases.ts +52 -0
- package/src/sources/index.ts +60 -0
- package/src/sources/mdx-remote.ts +76 -0
- package/src/sources/notion.ts +63 -0
- package/src/sources/obsidian.ts +38 -0
- package/src/sources/payload.ts +60 -0
- package/src/sources/registry.ts +182 -0
- package/src/sources/sanity.ts +66 -0
- package/src/sources/shared.ts +52 -0
- package/src/sources/strapi.ts +58 -0
- package/src/theme/entry.ts +47 -2
- package/src/translate/report.ts +40 -7
- package/src/upgrade/upgrade.ts +499 -0
- package/dist/cli/chunk-12dxjqk7.js.map +0 -10
- package/dist/cli/chunk-196vjxp9.js.map +0 -13
- package/dist/cli/chunk-2mzebbbz.js +0 -69
- package/dist/cli/chunk-2z47ypj8.js.map +0 -11
- package/dist/cli/chunk-30e87n55.js +0 -108
- package/dist/cli/chunk-30e87n55.js.map +0 -10
- package/dist/cli/chunk-450a7rcr.js +0 -185
- package/dist/cli/chunk-450a7rcr.js.map +0 -11
- package/dist/cli/chunk-5n7t497w.js.map +0 -40
- package/dist/cli/chunk-61j18dwk.js +0 -5342
- package/dist/cli/chunk-61j18dwk.js.map +0 -58
- package/dist/cli/chunk-88by27n5.js +0 -17
- package/dist/cli/chunk-88by27n5.js.map +0 -10
- package/dist/cli/chunk-8cd8tj54.js.map +0 -34
- package/dist/cli/chunk-aztttvb3.js +0 -381
- package/dist/cli/chunk-aztttvb3.js.map +0 -12
- package/dist/cli/chunk-cvky9gb2.js.map +0 -11
- package/dist/cli/chunk-ejjx8znq.js.map +0 -15
- package/dist/cli/chunk-fmceyezb.js +0 -1007
- package/dist/cli/chunk-fmceyezb.js.map +0 -13
- package/dist/cli/chunk-hdm2dkd2.js.map +0 -48
- package/dist/cli/chunk-hs3gbh8p.js.map +0 -10
- package/dist/cli/chunk-jbj4qhfw.js +0 -30
- package/dist/cli/chunk-jbj4qhfw.js.map +0 -10
- package/dist/cli/chunk-mqb2ka8m.js +0 -68
- package/dist/cli/chunk-mqb2ka8m.js.map +0 -10
- package/dist/cli/chunk-mt76t7dj.js.map +0 -11
- package/dist/cli/chunk-q4rae3bg.js +0 -60
- package/dist/cli/chunk-q4rae3bg.js.map +0 -10
- package/dist/cli/chunk-ra1v2nc2.js +0 -35
- package/dist/cli/chunk-ra1v2nc2.js.map +0 -10
- package/dist/cli/chunk-t3tj0dgr.js.map +0 -15
- package/dist/cli/chunk-tqa1s0k8.js +0 -69
- package/dist/cli/chunk-tqa1s0k8.js.map +0 -11
- package/dist/cli/chunk-vh9w1sgp.js +0 -73
- package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
- package/dist/cli/chunk-vkrsvbr5.js +0 -107
- package/dist/cli/chunk-vkrsvbr5.js.map +0 -11
- package/dist/cli/chunk-vrfp10qk.js +0 -81
- package/dist/cli/chunk-vrfp10qk.js.map +0 -10
- package/dist/cli/chunk-wjt80jps.js +0 -1049
- package/dist/cli/chunk-wjt80jps.js.map +0 -24
- package/docs/advanced/api-reference.mdx +0 -240
- package/docs/reference/cli.mdx +0 -197
- package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
- package/src/components/content/changelog-element.ts +0 -69
- package/src/search/providers.ts +0 -91
- /package/dist/cli/{chunk-3w7b2vcx.js.map → chunk-7ez8ny0t.js.map} +0 -0
- /package/dist/cli/{chunk-688e0dde.js.map → chunk-88cpgt6h.js.map} +0 -0
- /package/dist/cli/{chunk-exeeb35e.js.map → chunk-f7t03s3g.js.map} +0 -0
- /package/dist/cli/{chunk-ppfvdcd4.js.map → chunk-zxccj738.js.map} +0 -0
package/src/core/links.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import { basename, dirname, join, relative, resolve } from "pathe";
|
|
3
|
+
import { basename, dirname, join, normalize, relative, resolve } from "pathe";
|
|
4
4
|
|
|
5
5
|
import { stripBasePath, withBasePath } from "./base-path.ts";
|
|
6
6
|
import {
|
|
@@ -80,6 +80,8 @@ interface LinkContext {
|
|
|
80
80
|
/** Servable routes outside the graph (custom pages, generated routes); their
|
|
81
81
|
* headings are unknown, so anchors there are accepted unchecked. */
|
|
82
82
|
extraRoutes: Set<string>;
|
|
83
|
+
/** Where content files publish, for file links (`./setup.mdx`). */
|
|
84
|
+
fileRoutes: FileRouteIndex;
|
|
83
85
|
/** Locale routing, when the site is multi-locale; drives served-route resolution. */
|
|
84
86
|
i18n: LocaleRouting | null;
|
|
85
87
|
publicDir: string | null;
|
|
@@ -156,6 +158,81 @@ const toRoute = (path: string): string => {
|
|
|
156
158
|
return route === "" ? "/" : route;
|
|
157
159
|
};
|
|
158
160
|
|
|
161
|
+
/** The page a relative link is written on, as the resolver sees it. */
|
|
162
|
+
export interface RelativeLinkBase {
|
|
163
|
+
/** Whether the page is its folder's index (its route is its directory). */
|
|
164
|
+
isIndex: boolean;
|
|
165
|
+
/** The page's own route, base path included. */
|
|
166
|
+
route: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** A root-relative path, a bare `#fragment` or `?query`, or any scheme. */
|
|
170
|
+
const NOT_RELATIVE = /^(?:[#?/]|[a-z][a-z0-9+.-]*:)/iu;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Where a relative page link written on `from` lands: a root-relative route
|
|
174
|
+
* with the authored `?query#hash` kept — or `undefined` when `href` isn't a
|
|
175
|
+
* relative page link (a root-relative path, a bare `#fragment` or `?query`,
|
|
176
|
+
* an external URL or other scheme, or a relative asset like `./diagram.png`).
|
|
177
|
+
*
|
|
178
|
+
* The one reading `blume validate` checks links against and the Markdown
|
|
179
|
+
* pipeline rewrites them to, so the built `href`, the link check, and the
|
|
180
|
+
* browser agree. Relative paths resolve file-style: a leaf page's links
|
|
181
|
+
* resolve against its parent directory, while an index page's route already is
|
|
182
|
+
* its directory — `./install` on `guides/index.mdx` (`/guides`) lands on
|
|
183
|
+
* `/guides/install`, where a browser reading the slashless URL would go to
|
|
184
|
+
* `/install`. A `.md`/`.mdx` target is a file link: `resolveFile` maps its
|
|
185
|
+
* decoded path, relative to the linking file, to the route that file
|
|
186
|
+
* publishes at, so a target with its own `slug` or an ordering prefix still
|
|
187
|
+
* lands on its page instead of on its raw Markdown source. Without
|
|
188
|
+
* `resolveFile`, or for a file it doesn't know, the target resolves
|
|
189
|
+
* route-relative with the extension dropped.
|
|
190
|
+
*
|
|
191
|
+
* Any other extension (`./diagram.png`) marks an asset, except where a page
|
|
192
|
+
* publishes at the resolved path: `hasRoute` answers that, so a dotted page
|
|
193
|
+
* name (`./node.js` for `node.js.mdx`, `./v1.2`) is still a page link.
|
|
194
|
+
*/
|
|
195
|
+
export const resolveRelativeHref = (
|
|
196
|
+
href: string,
|
|
197
|
+
from: RelativeLinkBase,
|
|
198
|
+
resolveFile?: (path: string) => string | undefined,
|
|
199
|
+
hasRoute?: (route: string) => boolean
|
|
200
|
+
): string | undefined => {
|
|
201
|
+
if (href === "" || NOT_RELATIVE.test(href)) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
const suffixAt = href.search(/[?#]/u);
|
|
205
|
+
const path = suffixAt === -1 ? href : href.slice(0, suffixAt);
|
|
206
|
+
const suffix = suffixAt === -1 ? "" : href.slice(suffixAt);
|
|
207
|
+
if (FILE_EXT.test(path) && !DOC_EXT.test(path)) {
|
|
208
|
+
const route = toRoute(resolveRelative(from.route, path, from.isIndex));
|
|
209
|
+
return hasRoute?.(decodePercent(route)) ? `${route}${suffix}` : undefined;
|
|
210
|
+
}
|
|
211
|
+
const fileRoute = DOC_EXT.test(path)
|
|
212
|
+
? resolveFile?.(decodePercent(path))
|
|
213
|
+
: undefined;
|
|
214
|
+
return `${fileRoute ?? toRoute(resolveRelative(from.route, path, from.isIndex))}${suffix}`;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Whether a content file is its folder's index, from its name as written on
|
|
219
|
+
* disk: `index.md(x)` after an ordering prefix, optionally carrying one of
|
|
220
|
+
* `localeTokens` before the extension (`index.fr.mdx` under the `dot` locale
|
|
221
|
+
* parser, `index.$.mdx` for a file shared by every locale).
|
|
222
|
+
*/
|
|
223
|
+
export const isIndexFileName = (
|
|
224
|
+
name: string,
|
|
225
|
+
localeTokens: readonly string[] = []
|
|
226
|
+
): boolean => {
|
|
227
|
+
const stem = basename(name).replace(NUMERIC_PREFIX, "");
|
|
228
|
+
const match = /^index(?:\.(?<token>[^./]+))?\.(?:md|mdx)$/iu.exec(stem);
|
|
229
|
+
if (!match) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
const token = match.groups?.token;
|
|
233
|
+
return token === undefined || localeTokens.includes(token);
|
|
234
|
+
};
|
|
235
|
+
|
|
159
236
|
/** Build a map of route -> set of heading anchor slugs. */
|
|
160
237
|
const buildAnchorIndex = (pages: PageRecord[]): Map<string, Set<string>> => {
|
|
161
238
|
const anchors = new Map<string, Set<string>>();
|
|
@@ -329,6 +406,92 @@ const checkExternalLinks = async (
|
|
|
329
406
|
return diagnostics;
|
|
330
407
|
};
|
|
331
408
|
|
|
409
|
+
/** Where content files publish, for resolving file links (`./setup.mdx`). */
|
|
410
|
+
export interface FileRouteIndex {
|
|
411
|
+
/**
|
|
412
|
+
* Absolute source path → the route that file publishes at. A file shared by
|
|
413
|
+
* every locale publishes once per locale; the default locale's route stands
|
|
414
|
+
* for it (a link from a localized page moves into that locale afterwards,
|
|
415
|
+
* exactly as the rendered link does). Fallback copies render another
|
|
416
|
+
* locale's file, so they never stand for it.
|
|
417
|
+
*/
|
|
418
|
+
bySource: Map<string, string>;
|
|
419
|
+
/**
|
|
420
|
+
* A default-locale page's locale-stripped path (`navPath`) → its route. A
|
|
421
|
+
* page in a locale folder that links a sibling not translated yet
|
|
422
|
+
* (`fr/guides/setup.mdx` missing) means the default tree's file
|
|
423
|
+
* (`guides/setup.mdx`), whose route — its own `slug` included — then moves
|
|
424
|
+
* into the reader's locale onto the fallback copy.
|
|
425
|
+
*/
|
|
426
|
+
byDefaultNavPath: Map<string, string>;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** The linking side of a file link: where the page's source lives. */
|
|
430
|
+
export interface FileLinkBase {
|
|
431
|
+
navPath: string;
|
|
432
|
+
sourcePath: string;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export const buildFileRouteIndex = (
|
|
436
|
+
pages: readonly PageRecord[],
|
|
437
|
+
i18n: LocaleRouting | null
|
|
438
|
+
): FileRouteIndex => {
|
|
439
|
+
const bySource = new Map<string, string>();
|
|
440
|
+
const byDefaultNavPath = new Map<string, string>();
|
|
441
|
+
for (const page of pages) {
|
|
442
|
+
const { sourcePath } = page;
|
|
443
|
+
if (!sourcePath || page.fallback) {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
const isDefault = page.locale === i18n?.defaultLocale;
|
|
447
|
+
if (!bySource.has(sourcePath) || isDefault) {
|
|
448
|
+
bySource.set(sourcePath, page.route);
|
|
449
|
+
}
|
|
450
|
+
if (isDefault) {
|
|
451
|
+
byDefaultNavPath.set(normalize(page.navPath), page.route);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return { byDefaultNavPath, bySource };
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* The route a file link written on `from` lands on: the linked file's own
|
|
459
|
+
* route, or — when a locale folder doesn't have that file yet — the default
|
|
460
|
+
* tree's file at the same place.
|
|
461
|
+
*/
|
|
462
|
+
export const routeOfLinkedFile = (
|
|
463
|
+
index: FileRouteIndex,
|
|
464
|
+
from: FileLinkBase,
|
|
465
|
+
path: string
|
|
466
|
+
): string | undefined =>
|
|
467
|
+
index.bySource.get(resolve(dirname(from.sourcePath), path)) ??
|
|
468
|
+
index.byDefaultNavPath.get(normalize(join(dirname(from.navPath), path)));
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* The path a relative link on `page` resolves to — the same reading the
|
|
472
|
+
* Markdown pipeline rewrites the rendered `href` to (see
|
|
473
|
+
* {@link resolveRelativeHref}), so what's checked is what ships. A relative
|
|
474
|
+
* asset (`./diagram.png`) isn't a page link; it resolves against the route's
|
|
475
|
+
* directory for the public-dir probe.
|
|
476
|
+
*/
|
|
477
|
+
const relativeTarget = (
|
|
478
|
+
page: PageRecord,
|
|
479
|
+
rawPath: string,
|
|
480
|
+
ctx: LinkContext
|
|
481
|
+
): string => {
|
|
482
|
+
const base = { isIndex: isIndexPage(page), route: page.route };
|
|
483
|
+
const { navPath, sourcePath } = page;
|
|
484
|
+
const resolveFile = sourcePath
|
|
485
|
+
? (path: string) =>
|
|
486
|
+
routeOfLinkedFile(ctx.fileRoutes, { navPath, sourcePath }, path)
|
|
487
|
+
: undefined;
|
|
488
|
+
return (
|
|
489
|
+
resolveRelativeHref(rawPath, base, resolveFile, (route) =>
|
|
490
|
+
ctx.routes.has(route)
|
|
491
|
+
) ?? resolveRelative(page.route, rawPath, base.isIndex)
|
|
492
|
+
);
|
|
493
|
+
};
|
|
494
|
+
|
|
332
495
|
/** Classify a single link, queueing external refs via `onExternal`. */
|
|
333
496
|
const classifyLink = (
|
|
334
497
|
page: PageRecord,
|
|
@@ -382,7 +545,7 @@ const classifyLink = (
|
|
|
382
545
|
|
|
383
546
|
const resolved = rawPath.startsWith("/")
|
|
384
547
|
? rawPath
|
|
385
|
-
:
|
|
548
|
+
: relativeTarget(page, rawPath, ctx);
|
|
386
549
|
return checkPathLink(resolved, fragment, page, link, site, ctx, via);
|
|
387
550
|
};
|
|
388
551
|
|
|
@@ -416,6 +579,7 @@ export const validateLinks = async (
|
|
|
416
579
|
anchors: buildAnchorIndex(graph.pages),
|
|
417
580
|
basePath,
|
|
418
581
|
extraRoutes: new Set((options.extraRoutes ?? []).map(toRoute)),
|
|
582
|
+
fileRoutes: buildFileRouteIndex(graph.pages, options.i18n ?? null),
|
|
419
583
|
i18n: options.i18n ?? null,
|
|
420
584
|
publicDir: options.publicDir,
|
|
421
585
|
redirects: new Set(
|
package/src/core/manifest.ts
CHANGED
|
@@ -82,9 +82,14 @@ const buildFallbackRoutes = (
|
|
|
82
82
|
if (!fallback) {
|
|
83
83
|
return [];
|
|
84
84
|
}
|
|
85
|
+
// A monolingual page (a GitHub release) publishes in one language only, so it
|
|
86
|
+
// gets no copy at every other locale's URL: those would be duplicates of the
|
|
87
|
+
// same text under a translated chrome.
|
|
85
88
|
const fallbackPages = new Map(
|
|
86
89
|
graph.pages.flatMap((page) =>
|
|
87
|
-
page.locale === fallback
|
|
90
|
+
page.locale === fallback && !page.monolingual
|
|
91
|
+
? [[page.translationKey, page] as const]
|
|
92
|
+
: []
|
|
88
93
|
)
|
|
89
94
|
);
|
|
90
95
|
const routes: RouteManifestEntry[] = [];
|
|
@@ -126,6 +131,7 @@ const buildFallbackRoutes = (
|
|
|
126
131
|
indexable: false,
|
|
127
132
|
lastModified: source.lastModified,
|
|
128
133
|
locale: code,
|
|
134
|
+
monolingual: source.monolingual,
|
|
129
135
|
path,
|
|
130
136
|
source: source.source,
|
|
131
137
|
sourcePath: source.sourcePath,
|
|
@@ -145,7 +151,7 @@ export const buildManifest = (options: {
|
|
|
145
151
|
graph: ContentGraph;
|
|
146
152
|
}): BlumeManifest => {
|
|
147
153
|
const { context, config, graph } = options;
|
|
148
|
-
const searchEnabled = config.search.provider !== "none";
|
|
154
|
+
const searchEnabled = config.search.provider.mode !== "none";
|
|
149
155
|
const { i18n } = config;
|
|
150
156
|
|
|
151
157
|
// Real translations per logical page, for `hreflang` and the switcher. Built
|
|
@@ -189,6 +195,7 @@ export const buildManifest = (options: {
|
|
|
189
195
|
indexable: searchEnabled && contentIndexable(page, config),
|
|
190
196
|
lastModified: page.lastModified,
|
|
191
197
|
locale: page.locale,
|
|
198
|
+
monolingual: page.monolingual,
|
|
192
199
|
path: page.route,
|
|
193
200
|
source: page.source,
|
|
194
201
|
sourcePath: page.sourcePath,
|
|
@@ -234,7 +241,7 @@ export const buildManifest = (options: {
|
|
|
234
241
|
return {
|
|
235
242
|
blumeVersion: getBlumeVersion(),
|
|
236
243
|
contentRoot: context.contentRoot,
|
|
237
|
-
output: config.deployment.output,
|
|
244
|
+
output: config.deployment.options.output,
|
|
238
245
|
projectRoot: context.root,
|
|
239
246
|
routes,
|
|
240
247
|
version: MANIFEST_VERSION,
|
package/src/core/navigation.ts
CHANGED
|
@@ -43,12 +43,66 @@ export const isUnderPath = (route: string, base: string): boolean =>
|
|
|
43
43
|
export const isRootTab = (tab: NavTab, root: string): boolean =>
|
|
44
44
|
isUnderPath(root, tab.path);
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* A page's sidebar icon: `sidebar.icon`, or the top-level `icon` shorthand
|
|
48
|
+
* (the Mintlify-style spelling) when the nested key is unset.
|
|
49
|
+
*/
|
|
50
|
+
const sidebarIcon = (page: PageRecord): string | undefined =>
|
|
51
|
+
page.meta.sidebar.icon ?? page.meta.icon;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Words a folder name spells in lowercase that read wrong capitalized: the
|
|
55
|
+
* acronyms and brand casings docs folders are named after (`api-reference`
|
|
56
|
+
* is "API Reference", not "Api Reference").
|
|
57
|
+
*/
|
|
58
|
+
const WORD_FORMS = new Map([
|
|
59
|
+
["ai", "AI"],
|
|
60
|
+
["api", "API"],
|
|
61
|
+
["apis", "APIs"],
|
|
62
|
+
["asyncapi", "AsyncAPI"],
|
|
63
|
+
["cli", "CLI"],
|
|
64
|
+
["css", "CSS"],
|
|
65
|
+
["faq", "FAQ"],
|
|
66
|
+
["faqs", "FAQs"],
|
|
67
|
+
["graphql", "GraphQL"],
|
|
68
|
+
["html", "HTML"],
|
|
69
|
+
["http", "HTTP"],
|
|
70
|
+
["https", "HTTPS"],
|
|
71
|
+
["id", "ID"],
|
|
72
|
+
["ids", "IDs"],
|
|
73
|
+
["ios", "iOS"],
|
|
74
|
+
["js", "JS"],
|
|
75
|
+
["json", "JSON"],
|
|
76
|
+
["jwt", "JWT"],
|
|
77
|
+
["llm", "LLM"],
|
|
78
|
+
["llms", "LLMs"],
|
|
79
|
+
["macos", "macOS"],
|
|
80
|
+
["mcp", "MCP"],
|
|
81
|
+
["oauth", "OAuth"],
|
|
82
|
+
["openapi", "OpenAPI"],
|
|
83
|
+
["rss", "RSS"],
|
|
84
|
+
["sdk", "SDK"],
|
|
85
|
+
["sdks", "SDKs"],
|
|
86
|
+
["seo", "SEO"],
|
|
87
|
+
["sql", "SQL"],
|
|
88
|
+
["sso", "SSO"],
|
|
89
|
+
["ts", "TS"],
|
|
90
|
+
["ui", "UI"],
|
|
91
|
+
["url", "URL"],
|
|
92
|
+
["urls", "URLs"],
|
|
93
|
+
["xml", "XML"],
|
|
94
|
+
["yaml", "YAML"],
|
|
95
|
+
]);
|
|
96
|
+
|
|
46
97
|
const humanize = (segment: string): string =>
|
|
47
98
|
segment
|
|
48
99
|
.replace(NUMERIC_PREFIX, "")
|
|
49
100
|
.split(WORD_SPLIT)
|
|
50
101
|
.filter(Boolean)
|
|
51
|
-
.map(
|
|
102
|
+
.map(
|
|
103
|
+
(word) =>
|
|
104
|
+
WORD_FORMS.get(word) ?? word.charAt(0).toUpperCase() + word.slice(1)
|
|
105
|
+
)
|
|
52
106
|
.join(" ");
|
|
53
107
|
|
|
54
108
|
const numericOrder = (segment: string): number => {
|
|
@@ -112,6 +166,8 @@ interface MutableGroup {
|
|
|
112
166
|
path: string;
|
|
113
167
|
/** The group's URL path (folder route prefix); set as pages are inserted. */
|
|
114
168
|
routePath?: string;
|
|
169
|
+
/** The folder's index page route, when it has one; the group row's link. */
|
|
170
|
+
route?: string;
|
|
115
171
|
label: string;
|
|
116
172
|
icon?: string;
|
|
117
173
|
collapsed?: boolean;
|
|
@@ -214,8 +270,14 @@ const applyFolderMeta = (
|
|
|
214
270
|
sharedMeta: Map<string, FolderMeta>,
|
|
215
271
|
metaPrefix: string,
|
|
216
272
|
sharedMetaPrefix: string,
|
|
217
|
-
indexDisplay: Map<string, SidebarDisplay
|
|
273
|
+
indexDisplay: Map<string, SidebarDisplay>,
|
|
274
|
+
indexRoute: Map<string, string>
|
|
218
275
|
): void => {
|
|
276
|
+
// A folder with an index page links its group row to it — the same shape
|
|
277
|
+
// as an explicit-config group's `root`, and the only sidebar link to the
|
|
278
|
+
// section's own page once the index row is hidden. Index-less folders keep
|
|
279
|
+
// no link: their row would 404.
|
|
280
|
+
group.route = indexRoute.get(group.path);
|
|
219
281
|
// Locale-specific meta wins; a shared `meta.$.*` (keyed by the locale-stripped
|
|
220
282
|
// group path — version-prefixed inside a snapshot) applies to every locale
|
|
221
283
|
// otherwise.
|
|
@@ -254,7 +316,8 @@ const applyFolderMeta = (
|
|
|
254
316
|
sharedMeta,
|
|
255
317
|
metaPrefix,
|
|
256
318
|
sharedMetaPrefix,
|
|
257
|
-
indexDisplay
|
|
319
|
+
indexDisplay,
|
|
320
|
+
indexRoute
|
|
258
321
|
);
|
|
259
322
|
}
|
|
260
323
|
}
|
|
@@ -267,6 +330,12 @@ const applyFolderMeta = (
|
|
|
267
330
|
* update the folder's `meta.ts` and forget the index page's own frontmatter
|
|
268
331
|
* (or vice versa), and a correct-looking sidebar hides the mismatch.
|
|
269
332
|
*
|
|
333
|
+
* Only fires when the index page's own sidebar row is hidden
|
|
334
|
+
* (`sidebar.hidden`), so the linked group header is the only sidebar label the
|
|
335
|
+
* page has. A visible index row shows the page's own label beneath the header,
|
|
336
|
+
* so the sidebar already carries both titles and a divergence there is a
|
|
337
|
+
* deliberate pairing ("CLI" over "Overview"), not drift.
|
|
338
|
+
*
|
|
270
339
|
* Only fires when the page has an explicit frontmatter `title` of its own:
|
|
271
340
|
* when it's absent, `page.title` is derived from the first heading or the
|
|
272
341
|
* filename, so it almost never coincidentally matches a custom folder title —
|
|
@@ -289,7 +358,11 @@ const indexTitleMismatchDiagnostic = (
|
|
|
289
358
|
metaPrefix: string,
|
|
290
359
|
sharedMetaPrefix: string
|
|
291
360
|
): Diagnostic | undefined => {
|
|
292
|
-
if (
|
|
361
|
+
if (
|
|
362
|
+
!(page.meta.title && page.meta.sidebar.hidden) ||
|
|
363
|
+
page.fallback ||
|
|
364
|
+
folderPath === ""
|
|
365
|
+
) {
|
|
293
366
|
return undefined;
|
|
294
367
|
}
|
|
295
368
|
const meta =
|
|
@@ -510,6 +583,7 @@ const toNavNode = (node: MutableNode, display: SidebarDisplay): NavNode => {
|
|
|
510
583
|
kind: "group",
|
|
511
584
|
label: node.label,
|
|
512
585
|
path: node.routePath,
|
|
586
|
+
route: node.route,
|
|
513
587
|
};
|
|
514
588
|
};
|
|
515
589
|
|
|
@@ -529,6 +603,11 @@ const buildFileSystemSidebar = (
|
|
|
529
603
|
// Collected before the hidden filter (like the title check): hiding the index
|
|
530
604
|
// row from the panel shouldn't stop it configuring its group.
|
|
531
605
|
const indexDisplay = new Map<string, SidebarDisplay>();
|
|
606
|
+
// Folder path -> that folder's index page route, for the group row's link.
|
|
607
|
+
// Also collected before the hidden filter: hiding the index row is how a
|
|
608
|
+
// site drops the duplicate label under a linked header, so the link must
|
|
609
|
+
// survive it. The content root is not a group, so its index is skipped.
|
|
610
|
+
const indexRoute = new Map<string, string>();
|
|
532
611
|
|
|
533
612
|
for (const page of pages) {
|
|
534
613
|
// Group by the locale-stripped path so the locale dir is not a nav group.
|
|
@@ -537,8 +616,9 @@ const buildFileSystemSidebar = (
|
|
|
537
616
|
const stem = stemOf(filename);
|
|
538
617
|
const dirs = parts.slice(0, -1);
|
|
539
618
|
|
|
540
|
-
// Checked before the hidden filter:
|
|
541
|
-
//
|
|
619
|
+
// Checked before the hidden filter: the title check fires only for a
|
|
620
|
+
// sidebar-hidden index page, whose own <title> the header label stands in
|
|
621
|
+
// for, so it must see the pages the filter drops.
|
|
542
622
|
if (isIndexStem(stem)) {
|
|
543
623
|
const diagnostic = indexTitleMismatchDiagnostic(
|
|
544
624
|
page,
|
|
@@ -558,6 +638,9 @@ const buildFileSystemSidebar = (
|
|
|
558
638
|
if (page.meta.sidebar.display && !page.fallback) {
|
|
559
639
|
indexDisplay.set(dirs.join("/"), page.meta.sidebar.display);
|
|
560
640
|
}
|
|
641
|
+
if (dirs.length > 0) {
|
|
642
|
+
indexRoute.set(dirs.join("/"), page.route);
|
|
643
|
+
}
|
|
561
644
|
}
|
|
562
645
|
|
|
563
646
|
if (page.meta.sidebar.hidden) {
|
|
@@ -594,7 +677,7 @@ const buildFileSystemSidebar = (
|
|
|
594
677
|
deprecated: page.meta.deprecated || undefined,
|
|
595
678
|
description: page.description,
|
|
596
679
|
file: page.sourcePath,
|
|
597
|
-
icon: page
|
|
680
|
+
icon: sidebarIcon(page),
|
|
598
681
|
key: segmentKey(stem),
|
|
599
682
|
kind: "page",
|
|
600
683
|
label: page.meta.sidebar.label ?? page.title,
|
|
@@ -611,7 +694,8 @@ const buildFileSystemSidebar = (
|
|
|
611
694
|
sharedMeta,
|
|
612
695
|
metaPrefix,
|
|
613
696
|
sharedMetaPrefix,
|
|
614
|
-
indexDisplay
|
|
697
|
+
indexDisplay,
|
|
698
|
+
indexRoute
|
|
615
699
|
);
|
|
616
700
|
sortNodes(root.children, diagnostics);
|
|
617
701
|
hoistPages(root.children, display, true);
|
|
@@ -672,7 +756,7 @@ const configItemToNode = (
|
|
|
672
756
|
badge: page.meta.sidebar.badge,
|
|
673
757
|
deprecated: page.meta.deprecated || undefined,
|
|
674
758
|
description: page.description,
|
|
675
|
-
icon: page
|
|
759
|
+
icon: sidebarIcon(page),
|
|
676
760
|
kind: "page",
|
|
677
761
|
label: page.meta.sidebar.label ?? page.title,
|
|
678
762
|
pageId: page.id,
|
|
@@ -741,10 +825,26 @@ const buildConfigSidebar = (
|
|
|
741
825
|
/**
|
|
742
826
|
* Resolve a tab's clickable target. A tab's `path` scopes its sidebar section
|
|
743
827
|
* but need not be a real route — a section with no index page would 404 if the
|
|
744
|
-
* tab linked straight to it. Prefer
|
|
745
|
-
*
|
|
828
|
+
* tab linked straight to it. Prefer the path itself when it's served outside
|
|
829
|
+
* the content tree (the generated changelog index) or is a page/group in the
|
|
830
|
+
* tree; otherwise fall back to the first linkable route in the section
|
|
831
|
+
* (sidebar order).
|
|
832
|
+
*
|
|
833
|
+
* Routes outside the content tree are served at their own path, not under
|
|
834
|
+
* `basePath` (`pages/changelog.astro` answers `/changelog` on a `/docs`-based
|
|
835
|
+
* site), while tab paths arrive based (`/docs/changelog`). So when the based
|
|
836
|
+
* path is neither an outside route nor a tree node, the base-less path is
|
|
837
|
+
* checked against the outside routes before the section's first page wins.
|
|
746
838
|
*/
|
|
747
|
-
const resolveTabHref = (
|
|
839
|
+
const resolveTabHref = (
|
|
840
|
+
sidebar: NavNode[],
|
|
841
|
+
path: string,
|
|
842
|
+
extraRoutes: ReadonlySet<string>,
|
|
843
|
+
basePath: string
|
|
844
|
+
): string => {
|
|
845
|
+
if (extraRoutes.has(path)) {
|
|
846
|
+
return path;
|
|
847
|
+
}
|
|
748
848
|
let first: string | undefined;
|
|
749
849
|
const walk = (nodes: NavNode[]): boolean => {
|
|
750
850
|
for (const node of nodes) {
|
|
@@ -765,19 +865,30 @@ const resolveTabHref = (sidebar: NavNode[], path: string): string => {
|
|
|
765
865
|
}
|
|
766
866
|
return false;
|
|
767
867
|
};
|
|
768
|
-
|
|
868
|
+
if (walk(sidebar)) {
|
|
869
|
+
return path;
|
|
870
|
+
}
|
|
871
|
+
const bare = stripBasePath(basePath, path);
|
|
872
|
+
return extraRoutes.has(bare) ? bare : (first ?? path);
|
|
769
873
|
};
|
|
770
874
|
|
|
771
875
|
/**
|
|
772
876
|
* Attach a resolved `href` to each tab whose section has no index page. An
|
|
773
877
|
* author-declared `href` is the tab's stated target, so it's kept as-is —
|
|
774
878
|
* resolution only fills in the tabs that didn't declare one. That's what lets a
|
|
775
|
-
* tab point at a route outside the content tree (a
|
|
776
|
-
*
|
|
879
|
+
* tab point at a route outside the content tree that resolution can't see (a
|
|
880
|
+
* custom `.astro` page); the generated changelog index arrives in
|
|
881
|
+
* `extraRoutes`, so a `/changelog` tab needs no `href`.
|
|
777
882
|
*/
|
|
778
|
-
const withTabHrefs = (
|
|
883
|
+
const withTabHrefs = (
|
|
884
|
+
tabs: NavTab[],
|
|
885
|
+
sidebar: NavNode[],
|
|
886
|
+
extraRoutes: ReadonlySet<string>,
|
|
887
|
+
basePath: string
|
|
888
|
+
): NavTab[] =>
|
|
779
889
|
tabs.map((tab) => {
|
|
780
|
-
const href =
|
|
890
|
+
const href =
|
|
891
|
+
tab.href ?? resolveTabHref(sidebar, tab.path, extraRoutes, basePath);
|
|
781
892
|
return href === tab.path ? tab : { ...tab, href };
|
|
782
893
|
});
|
|
783
894
|
|
|
@@ -894,6 +1005,12 @@ export const buildNavigation = (
|
|
|
894
1005
|
* into in place; omit to discard.
|
|
895
1006
|
*/
|
|
896
1007
|
diagnostics?: Diagnostic[];
|
|
1008
|
+
/**
|
|
1009
|
+
* Routes served outside the content tree that a tab `path` may name
|
|
1010
|
+
* directly (the generated changelog index), so the tab links there instead
|
|
1011
|
+
* of falling back to its section's first page.
|
|
1012
|
+
*/
|
|
1013
|
+
extraRoutes?: ReadonlySet<string>;
|
|
897
1014
|
}
|
|
898
1015
|
): Navigation => {
|
|
899
1016
|
const basePath = options.basePath ?? "";
|
|
@@ -901,6 +1018,7 @@ export const buildNavigation = (
|
|
|
901
1018
|
const metaPrefix = options.metaPrefix ?? "";
|
|
902
1019
|
const sharedMetaPrefix = options.sharedMetaPrefix ?? "";
|
|
903
1020
|
const sharedFolderMeta = options.sharedFolderMeta ?? new Map();
|
|
1021
|
+
const extraRoutes = options.extraRoutes ?? new Set<string>();
|
|
904
1022
|
|
|
905
1023
|
// Content-derived sidebar routes are already based via `page.route`; the
|
|
906
1024
|
// based tab paths also feed tab-scoping below, so they must agree with the
|
|
@@ -962,7 +1080,7 @@ export const buildNavigation = (
|
|
|
962
1080
|
root: rootTabPath,
|
|
963
1081
|
selectors,
|
|
964
1082
|
sidebar,
|
|
965
|
-
tabs: withTabHrefs(tabs, sidebar),
|
|
1083
|
+
tabs: withTabHrefs(tabs, sidebar, extraRoutes, basePath),
|
|
966
1084
|
};
|
|
967
1085
|
}
|
|
968
1086
|
|
|
@@ -985,6 +1103,6 @@ export const buildNavigation = (
|
|
|
985
1103
|
root: rootTabPath,
|
|
986
1104
|
selectors,
|
|
987
1105
|
sidebar,
|
|
988
|
-
tabs: withTabHrefs(tabs, sidebar),
|
|
1106
|
+
tabs: withTabHrefs(tabs, sidebar, extraRoutes, basePath),
|
|
989
1107
|
};
|
|
990
1108
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Links that open in a new tab. Every such link Blume renders — chrome (header
|
|
3
|
+
* actions, featured sidebar links, page actions), content components (Card,
|
|
4
|
+
* Tile, Tooltip), and Markdown links under `markdown.externalLinks` — points
|
|
5
|
+
* `aria-describedby` at one hidden, localized "Opens in a new tab" element each
|
|
6
|
+
* layout renders once per page, so screen-reader users hear the same warning
|
|
7
|
+
* sighted readers get from the arrow icon or the new tab itself.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { isExternalUrl } from "./base-path.ts";
|
|
11
|
+
|
|
12
|
+
/** The id of the layout's hidden "Opens in a new tab" description. */
|
|
13
|
+
export const NEW_TAB_HINT_ID = "blume-new-tab-hint";
|
|
14
|
+
|
|
15
|
+
/** The attributes a new-tab link carries (spread onto an `<a>`). */
|
|
16
|
+
export interface NewTabAttrs {
|
|
17
|
+
"aria-describedby"?: string;
|
|
18
|
+
rel?: string;
|
|
19
|
+
target?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** A link that always opens in a new tab (a repo link, an edit link). */
|
|
23
|
+
export const NEW_TAB_ATTRS: NewTabAttrs = {
|
|
24
|
+
"aria-describedby": NEW_TAB_HINT_ID,
|
|
25
|
+
rel: "noreferrer",
|
|
26
|
+
target: "_blank",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* {@link NEW_TAB_ATTRS} for an external href (the shared `isExternalUrl`
|
|
31
|
+
* predicate), and nothing for a site route, fragment, or `mailto:` link, which
|
|
32
|
+
* stay in the current tab.
|
|
33
|
+
*/
|
|
34
|
+
export const newTabAttrs = (href?: string): NewTabAttrs =>
|
|
35
|
+
href !== undefined && isExternalUrl(href) ? NEW_TAB_ATTRS : {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Node's own `require`, for the SDKs and heavy modules Blume loads only when a
|
|
5
|
+
* feature needs them. Resolution starts from this file, inside the installed
|
|
6
|
+
* package, exactly like the `import()` it stands in for, and Node 22.12+ loads
|
|
7
|
+
* ES modules through it too.
|
|
8
|
+
*
|
|
9
|
+
* Never `import()` in their place. When Node can't import the generated Astro
|
|
10
|
+
* config itself — it refuses to strip types from TypeScript under
|
|
11
|
+
* `node_modules`, which is where an installed Blume's runtime source lives —
|
|
12
|
+
* Astro evaluates the config, and every Blume module it reaches, in a Vite
|
|
13
|
+
* module runner that it closes as soon as the config has loaded. A dynamic
|
|
14
|
+
* `import()` in one of those modules resolves through that runner, so a call
|
|
15
|
+
* made any later (an `astro:build:done` hook, a Markdown plugin) throws "Vite
|
|
16
|
+
* module runner has been closed". `require` is Node's, so it works however the
|
|
17
|
+
* calling module was evaluated. The repo itself never sees the failure: its
|
|
18
|
+
* workspace link puts Blume outside `node_modules`, so Node imports the config
|
|
19
|
+
* natively.
|
|
20
|
+
*/
|
|
21
|
+
export const nodeRequire = createRequire(import.meta.url);
|