summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiDeoo2025-05-08 09:44:47 +0200
committerGitHub2025-05-08 09:44:47 +0200
commit449c8229effaab19ece3c0a34e32595809c33cc8 (patch)
tree6f78da7213c5ce737712db24f662dbd1813f5cfd
parentbe0028643590edfdff35b142d357dce452d13ec1 (diff)
downloadIT.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>
-rw-r--r--.changeset/pink-cameras-perform.md5
-rw-r--r--packages/starlight/__e2e__/components.test.ts15
-rw-r--r--packages/starlight/__e2e__/fixtures/basics/src/content.config.ts8
-rw-r--r--packages/starlight/__e2e__/fixtures/basics/src/content/reviews/alice.mdx12
-rw-r--r--packages/starlight/__e2e__/fixtures/basics/src/pages/markdown-page.md10
-rw-r--r--packages/starlight/__e2e__/fixtures/basics/src/pages/reviews/[...review].astro21
-rw-r--r--packages/starlight/__tests__/remark-rehype/anchor-links.test.ts5
-rw-r--r--packages/starlight/integrations/heading-links.ts29
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