From d4404feeb09346081ff84bdd2440ec0423aaa276 Mon Sep 17 00:00:00 2001 From: Larkin Young Date: Mon, 16 Feb 2026 20:01:22 +0000 Subject: [PATCH 1/2] feat: make stripPrefixes optional with Starlight default stripPrefixes in ImportLinkTransformOptions is now optional, defaulting to ['src/content/docs'] (the Starlight content root). This eliminates repetitive boilerplate in consumer configs. --- packages/astro-github-loader/src/github.content.ts | 10 +++++----- packages/astro-github-loader/src/github.types.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/astro-github-loader/src/github.content.ts b/packages/astro-github-loader/src/github.content.ts index 0c0f4a3..14c3660 100644 --- a/packages/astro-github-loader/src/github.content.ts +++ b/packages/astro-github-loader/src/github.content.ts @@ -434,12 +434,12 @@ export async function toCollectionEntry({ if (options.linkTransform) { logger.verbose(`Applying link transformation to ${allFiles.length} files`); + // Resolve stripPrefixes with Starlight default + const stripPrefixes = options.linkTransform.stripPrefixes ?? ['src/content/docs']; + // Generate automatic link mappings from pathMappings const autoGeneratedMappings = options.includes - ? generateAutoLinkMappings( - options.includes, - options.linkTransform.stripPrefixes, - ) + ? generateAutoLinkMappings(options.includes, stripPrefixes) : []; // Combine auto-generated mappings with user-defined mappings @@ -453,7 +453,7 @@ export async function toCollectionEntry({ ); processedFiles = globalLinkTransform(allFiles, { - stripPrefixes: options.linkTransform.stripPrefixes, + stripPrefixes, customHandlers: options.linkTransform.customHandlers, linkMappings: allLinkMappings, logger, diff --git a/packages/astro-github-loader/src/github.types.ts b/packages/astro-github-loader/src/github.types.ts index 9439f99..77837a3 100644 --- a/packages/astro-github-loader/src/github.types.ts +++ b/packages/astro-github-loader/src/github.types.ts @@ -52,8 +52,8 @@ export interface LinkMapping { * Configuration for import link transformation */ export interface ImportLinkTransformOptions { - /** Base paths to strip from final URLs (e.g., ["src/content/docs"]) */ - stripPrefixes: string[]; + /** Base paths to strip from final URLs. Defaults to ["src/content/docs"] (Starlight convention). */ + stripPrefixes?: string[]; /** Custom handlers for special link types */ customHandlers?: LinkHandler[]; /** Link mappings to transform URLs in markdown links */ From 092f2813fd5feb43d6bb47d48b22fc81516d98b9 Mon Sep 17 00:00:00 2001 From: Larkin Young Date: Mon, 16 Feb 2026 21:33:37 +0000 Subject: [PATCH 2/2] Fix global linkMappings not matching bare-path links Bare-path links (e.g., "docs/markdown/autoapi/foo/") were incorrectly normalized as file-relative before global linkMappings could match them. Now global mappings are tried against the raw link path first; if none match, the existing normalized-path flow runs unchanged. --- .../src/github.link-transform.spec.ts | 26 +++++++++++++++++++ .../src/github.link-transform.ts | 18 +++++++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/astro-github-loader/src/github.link-transform.spec.ts b/packages/astro-github-loader/src/github.link-transform.spec.ts index 8333272..f068a02 100644 --- a/packages/astro-github-loader/src/github.link-transform.spec.ts +++ b/packages/astro-github-loader/src/github.link-transform.spec.ts @@ -120,6 +120,32 @@ describe("globalLinkTransform", () => { expect(result[0].content).toBe("[See other](/other/)"); }); + it("should apply global linkMappings to bare-path links before normalization", () => { + const files: ImportedFile[] = [ + createImportedFile( + "docs/markdown/capabilities/guide.md", + "src/content/docs/guide.md", + "[`AccountManager`](docs/markdown/autoapi/algokit_utils/accounts/account_manager/#algokit_utils.accounts.account_manager.AccountManager)", + ), + ]; + + const result = globalLinkTransform(files, { + stripPrefixes: ["src/content/docs"], + linkMappings: [ + { + pattern: /^docs\/markdown\/autoapi\/algokit_utils\/(.+)/, + replacement: "/docs/algokit-utils/python/latest/api/$1", + global: true, + }, + ], + logger, + }); + + expect(result[0].content).toBe( + "[`AccountManager`](/docs/algokit-utils/python/latest/api/accounts/account_manager/#algokit_utils.accounts.account_manager.AccountManager)", + ); + }); + it("should preserve anchors in transformed links", () => { const files: ImportedFile[] = [ createImportedFile( diff --git a/packages/astro-github-loader/src/github.link-transform.ts b/packages/astro-github-loader/src/github.link-transform.ts index 9c70df9..f39f0b6 100644 --- a/packages/astro-github-loader/src/github.link-transform.ts +++ b/packages/astro-github-loader/src/github.link-transform.ts @@ -314,6 +314,24 @@ function transformLink( const { path: linkPath, anchor } = extractAnchor(linkUrl); + // Try global linkMappings on the RAW link path before normalization. + // Bare-path links (e.g., "docs/markdown/autoapi/foo/") are repo-root-relative + // but normalizePath() treats them as file-relative, mangling the path. + // Applying global mappings first lets patterns match the link as written. + if (context.global.linkMappings) { + const globalMappings = context.global.linkMappings.filter((m) => m.global); + if (globalMappings.length > 0) { + const rawMapped = applyLinkMappings( + linkPath + anchor, + globalMappings, + context, + ); + if (rawMapped !== linkPath + anchor) { + return `[${linkText}](${rawMapped})`; + } + } + } + // Normalize the link path relative to current file FIRST const normalizedPath = normalizePath( linkPath,