From 0b4823d534abe517fac5efd97f6febb5965714fe Mon Sep 17 00:00:00 2001 From: HiDeoo Date: Mon, 7 Oct 2024 20:56:10 +0200 Subject: Fix link formatting issue with `build.format` set to `file` and a `base` (#2408) --- .changeset/dirty-masks-accept.md | 5 +++ .../starlight/__tests__/basics/format-path.test.ts | 42 +++++++++++++++++++--- packages/starlight/utils/createPathFormatter.ts | 6 ++-- 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 .changeset/dirty-masks-accept.md diff --git a/.changeset/dirty-masks-accept.md b/.changeset/dirty-masks-accept.md new file mode 100644 index 00000000..41e8729f --- /dev/null +++ b/.changeset/dirty-masks-accept.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes a link formatting issue when using the Astro `build.format` option set to `file` with a `base`. diff --git a/packages/starlight/__tests__/basics/format-path.test.ts b/packages/starlight/__tests__/basics/format-path.test.ts index 8a1736a0..0a148404 100644 --- a/packages/starlight/__tests__/basics/format-path.test.ts +++ b/packages/starlight/__tests__/basics/format-path.test.ts @@ -1,15 +1,20 @@ -import { describe, expect, test } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { createPathFormatter } from '../../utils/createPathFormatter'; type FormatPathOptions = Parameters[0]; const formatPath = (href: string, opts: FormatPathOptions) => createPathFormatter(opts)(href); -describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expected: string }> }>([ +describe.each<{ + options: FormatPathOptions; + tests: Array<{ path: string; base?: string; expected: string }>; +}>([ { options: { format: 'file', trailingSlash: 'ignore' }, tests: [ // index page { path: '/', expected: '/index.html' }, + // index page with base + { path: '/', base: '/base/', expected: '/base/index.html' }, // with trailing slash { path: '/reference/configuration/', expected: '/reference/configuration.html' }, // without trailing slash @@ -25,6 +30,8 @@ describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expecte tests: [ // index page { path: '/', expected: '/index.html' }, + // index page with base + { path: '/', base: '/base/', expected: '/base/index.html' }, // with trailing slash { path: '/reference/configuration/', expected: '/reference/configuration.html' }, // without trailing slash @@ -40,6 +47,8 @@ describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expecte tests: [ // index page { path: '/', expected: '/index.html' }, + // index page with base + { path: '/', base: '/base/', expected: '/base/index.html' }, // with trailing slash { path: '/reference/configuration/', expected: '/reference/configuration.html' }, // without trailing slash @@ -55,6 +64,8 @@ describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expecte tests: [ // index page { path: '/', expected: '/' }, + // index page with base + { path: '/', base: '/base/', expected: '/base/' }, // with trailing slash { path: '/reference/configuration/', expected: '/reference/configuration/' }, // without trailing slash @@ -70,6 +81,8 @@ describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expecte tests: [ // index page { path: '/', expected: '/' }, + // index page with base + { path: '/', base: '/base/', expected: '/base' }, // with trailing slash { path: '/reference/configuration/', expected: '/reference/configuration' }, // without trailing slash @@ -85,6 +98,8 @@ describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expecte tests: [ // index page { path: '/', expected: '/' }, + // index page with base + { path: '/', base: '/base/', expected: '/base/' }, // with trailing slash { path: '/reference/configuration/', expected: '/reference/configuration/' }, // without trailing slash @@ -98,8 +113,27 @@ describe.each<{ options: FormatPathOptions; tests: Array<{ path: string; expecte ])( 'formatPath() with { format: $options.format, trailingSlash: $options.trailingSlash }', ({ options, tests }) => { - test.each(tests)('returns $expected for $path', ({ path, expected }) => { - expect(formatPath(path, options)).toBe(expected); + test.each(tests)('returns $expected for $path', async ({ path, base, expected }) => { + // If the base is not set, test the path formatter and end the test. + if (!base) { + expect(formatPath(path, options)).toBe(expected); + return; + } + + // Otherwise, reset the modules registry so that re-importing `../../utils/createPathFormatter` + // re-evaluates the module and re-computes the base. Re-importing the module is necessary + // because top-level imports cannot be re-evaluated. + vi.resetModules(); + // Set the base URL. + vi.stubEnv('BASE_URL', base); + // Re-import the module to re-create the path formatter. + const { createPathFormatter } = await import('../../utils/createPathFormatter'); + const formatPathWithBase: typeof formatPath = (href, opts) => createPathFormatter(opts)(href); + + expect(formatPathWithBase(path, options)).toBe(expected); + + vi.unstubAllEnvs(); + vi.resetModules(); }); } ); diff --git a/packages/starlight/utils/createPathFormatter.ts b/packages/starlight/utils/createPathFormatter.ts index 09922997..52c9527c 100644 --- a/packages/starlight/utils/createPathFormatter.ts +++ b/packages/starlight/utils/createPathFormatter.ts @@ -40,12 +40,12 @@ function formatPath( const formatStrategy = formatStrategies[format]; const trailingSlashStrategy = trailingSlashStrategies[trailingSlash]; - // Add base - href = formatStrategy.addBase(href); - // Handle extension href = formatStrategy.handleExtension(href); + // Add base + href = formatStrategy.addBase(href); + // Skip trailing slash handling for `build.format: 'file'` if (format === 'file') return href; -- cgit