diff options
author | HiDeoo | 2025-05-08 09:44:47 +0200 |
---|---|---|
committer | GitHub | 2025-05-08 09:44:47 +0200 |
commit | 449c8229effaab19ece3c0a34e32595809c33cc8 (patch) | |
tree | 6f78da7213c5ce737712db24f662dbd1813f5cfd | |
parent | be0028643590edfdff35b142d357dce452d13ec1 (diff) | |
download | IT.starlight-449c8229effaab19ece3c0a34e32595809c33cc8.tar.gz IT.starlight-449c8229effaab19ece3c0a34e32595809c33cc8.tar.bz2 IT.starlight-449c8229effaab19ece3c0a34e32595809c33cc8.zip |
Prevent heading anchor links on non-Starlight content (#3181)
Co-authored-by: Eveeifyeve <88671402+Eveeifyeve@users.noreply.github.com>
Co-authored-by: florian-lefebvre <69633530+florian-lefebvre@users.noreply.github.com>
Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com>
Co-authored-by: MoustaphaDev <81974850+MoustaphaDev@users.noreply.github.com>
8 files changed, 99 insertions, 6 deletions
diff --git a/.changeset/pink-cameras-perform.md b/.changeset/pink-cameras-perform.md new file mode 100644 index 00000000..f211ef1b --- /dev/null +++ b/.changeset/pink-cameras-perform.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes an issue where all headings in Markdown and MDX content were rendered with a [clickable anchor link](https://starlight.astro.build/reference/configuration/#headinglinks), even in non-Starlight pages. diff --git a/packages/starlight/__e2e__/components.test.ts b/packages/starlight/__e2e__/components.test.ts index 7b536c78..85010436 100644 --- a/packages/starlight/__e2e__/components.test.ts +++ b/packages/starlight/__e2e__/components.test.ts @@ -391,6 +391,21 @@ test.describe('anchor headings', () => { expect(markdownHtml).toEqual(componentHtml); }); + + test('does not render headings anchor links for individual Markdown pages and entries not part of the `docs` collection', async ({ + getProdServer, + page, + }) => { + const starlight = await getProdServer(); + + // Individual Markdown page + await starlight.goto('/markdown-page'); + await expect(page.locator('.sl-anchor-link')).not.toBeAttached(); + + // Content entry from the `reviews` content collection + await starlight.goto('/reviews/alice'); + await expect(page.locator('.sl-anchor-link')).not.toBeAttached(); + }); }); test.describe('head propagation', () => { diff --git a/packages/starlight/__e2e__/fixtures/basics/src/content.config.ts b/packages/starlight/__e2e__/fixtures/basics/src/content.config.ts index d9ee8c9d..0181947e 100644 --- a/packages/starlight/__e2e__/fixtures/basics/src/content.config.ts +++ b/packages/starlight/__e2e__/fixtures/basics/src/content.config.ts @@ -1,7 +1,13 @@ -import { defineCollection } from 'astro:content'; +import { defineCollection, z } from 'astro:content'; import { docsLoader } from '@astrojs/starlight/loaders'; import { docsSchema } from '@astrojs/starlight/schema'; +import { glob } from 'astro/loaders'; export const collections = { docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), + // A collection not handled by Starlight. + reviews: defineCollection({ + loader: glob({ base: './src/content/reviews', pattern: `**/[^_]*.{md,mdx}` }), + schema: z.object({ title: z.string() }), + }), }; diff --git a/packages/starlight/__e2e__/fixtures/basics/src/content/reviews/alice.mdx b/packages/starlight/__e2e__/fixtures/basics/src/content/reviews/alice.mdx new file mode 100644 index 00000000..8230272c --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/basics/src/content/reviews/alice.mdx @@ -0,0 +1,12 @@ +--- +title: Review from Alice +--- + +# Review from Alice + +This is a review from Alice. + +## Description + +This content collection entry is not part of the Starlight `docs` collection. +It is used to test that anchor links for headings are not generated for non-docs collection entries. diff --git a/packages/starlight/__e2e__/fixtures/basics/src/pages/markdown-page.md b/packages/starlight/__e2e__/fixtures/basics/src/pages/markdown-page.md new file mode 100644 index 00000000..d3b8d9cf --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/basics/src/pages/markdown-page.md @@ -0,0 +1,10 @@ +--- +title: Individual Markdown Page +--- + +# Individual Markdown Page + +## Description + +This page is an [individual Markdown page](https://docs.astro.build/en/guides/markdown-content/#individual-markdown-pages). +It is used to test that anchor links for headings are not generated for individual Markdown pages. diff --git a/packages/starlight/__e2e__/fixtures/basics/src/pages/reviews/[...review].astro b/packages/starlight/__e2e__/fixtures/basics/src/pages/reviews/[...review].astro new file mode 100644 index 00000000..23a7cf0f --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/basics/src/pages/reviews/[...review].astro @@ -0,0 +1,21 @@ +--- +import { getEntry, render } from 'astro:content'; + +/** + * This route is used to test that anchor links for headings are not generated for non-docs + * collection entries. + */ + +export function getStaticPaths() { + return [{ params: { review: 'alice' } }]; +} + +// @ts-expect-error - we don't generate types for this test fixture before type-checking the entire +// project. +const entry = await getEntry('reviews', 'alice'); +if (!entry) throw new Error('Could not find Alice review entry.'); + +const { Content } = await render(entry); +--- + +<Content /> diff --git a/packages/starlight/__tests__/remark-rehype/anchor-links.test.ts b/packages/starlight/__tests__/remark-rehype/anchor-links.test.ts index f7b8bb5c..90b86f36 100644 --- a/packages/starlight/__tests__/remark-rehype/anchor-links.test.ts +++ b/packages/starlight/__tests__/remark-rehype/anchor-links.test.ts @@ -30,7 +30,10 @@ const processor = await createMarkdownProcessor({ rehypePlugins: [ ...starlightAutolinkHeadings({ starlightConfig, - astroConfig: { experimental: { headingIdCompat: false } }, + astroConfig: { + srcDir: astroConfig.srcDir, + experimental: { headingIdCompat: false }, + }, useTranslations, absolutePathToLang, }), diff --git a/packages/starlight/integrations/heading-links.ts b/packages/starlight/integrations/heading-links.ts index f5914486..ebb61d4a 100644 --- a/packages/starlight/integrations/heading-links.ts +++ b/packages/starlight/integrations/heading-links.ts @@ -6,6 +6,7 @@ import { h } from 'hastscript'; import type { Transformer } from 'unified'; import { SKIP, visit } from 'unist-util-visit'; import type { HookParameters, StarlightConfig } from '../types'; +import { resolveCollectionPath } from '../utils/collection'; const AnchorLinkIcon = h( 'span', @@ -24,10 +25,14 @@ const AnchorLinkIcon = h( * Add anchor links to headings. */ export default function rehypeAutolinkHeadings( - useTranslationsForLang: HookParameters<'config:setup'>['useTranslations'], - absolutePathToLang: HookParameters<'config:setup'>['absolutePathToLang'] + docsCollectionPath: string, + useTranslationsForLang: AutolinkHeadingsOptions['useTranslations'], + absolutePathToLang: AutolinkHeadingsOptions['absolutePathToLang'] ) { const transformer: Transformer<Root> = (tree, file) => { + // If the document is not part of the Starlight docs collection, skip it. + if (!normalizePath(file.path).startsWith(docsCollectionPath)) return; + const pageLang = absolutePathToLang(file.path); const t = useTranslationsForLang(pageLang); @@ -67,7 +72,9 @@ export default function rehypeAutolinkHeadings( interface AutolinkHeadingsOptions { starlightConfig: Pick<StarlightConfig, 'markdown'>; - astroConfig: { experimental: Pick<AstroConfig['experimental'], 'headingIdCompat'> }; + astroConfig: Pick<AstroConfig, 'srcDir'> & { + experimental: Pick<AstroConfig['experimental'], 'headingIdCompat'>; + }; useTranslations: HookParameters<'config:setup'>['useTranslations']; absolutePathToLang: HookParameters<'config:setup'>['absolutePathToLang']; } @@ -85,10 +92,24 @@ export const starlightAutolinkHeadings = ({ rehypeHeadingIds, { experimentalHeadingIdCompat: astroConfig.experimental?.headingIdCompat }, ], - rehypeAutolinkHeadings(useTranslations, absolutePathToLang), + rehypeAutolinkHeadings( + normalizePath(resolveCollectionPath('docs', astroConfig.srcDir)), + useTranslations, + absolutePathToLang + ), ] : []; +/** + * File path separators seems to be inconsistent on Windows when the rehype plugin is used on + * Markdown vs MDX files. + * For the time being, we normalize the path to unix style path. + */ +const backSlashRegex = /\\/g; +function normalizePath(path: string) { + return path.replace(backSlashRegex, '/'); +} + // This utility is inlined from https://github.com/syntax-tree/hast-util-heading-rank // Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com> // MIT License: https://github.com/syntax-tree/hast-util-heading-rank/blob/main/license |