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.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, 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 */