diff --git a/.changeset/true-buses-juggle.md b/.changeset/true-buses-juggle.md new file mode 100644 index 00000000000..8eba7e4b09e --- /dev/null +++ b/.changeset/true-buses-juggle.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes Starlight Markdown processing being potentially applied to files that should not be processed. diff --git a/packages/starlight/__tests__/markdown-processor/markdown-process.test.ts b/packages/starlight/__tests__/markdown-processor/markdown-process.test.ts new file mode 100644 index 00000000000..a68c6b26a8d --- /dev/null +++ b/packages/starlight/__tests__/markdown-processor/markdown-process.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, test } from 'vitest'; +import { + getMarkdownProcessorPaths, + shouldTransformPath, +} from '../../integrations/markdown-process'; +import { createPluginTestOptions } from '../test-utils'; + +const root = new URL('file:///path/to/project/'); +const srcDir = new URL('./src/', root); + +describe('getMarkdownProcessorPaths', () => { + test('returns allowed directory paths with trailing slashes', async () => { + const allowedPaths = await getAllowedPaths(['./src/content/comments']); + + expect(allowedPaths).toEqual([ + '/path/to/project/src/content/docs/', + '/path/to/project/src/content/comments/', + ]); + }); +}); + +describe('shouldTransformPath', () => { + const allowedPaths = [ + '/path/to/project/src/content/docs/', + '/path/to/project/src/content/comments/', + ]; + + test('transforms files in allowed paths', () => { + expect(shouldTransformPath('/path/to/project/src/content/docs/index.md', allowedPaths)).toBe( + true + ); + expect( + shouldTransformPath('/path/to/project/src/content/comments/index.md', allowedPaths) + ).toBe(true); + }); + + test('does not transform sibling paths sharing the same prefix of allowed paths', () => { + expect( + shouldTransformPath('/path/to/project/src/content/docs-test/index.md', allowedPaths) + ).toBe(false); + expect( + shouldTransformPath('/path/to/project/src/content/comments-test/index.md', allowedPaths) + ).toBe(false); + }); +}); + +async function getAllowedPaths(processedDirs: string[] = []) { + const options = await createPluginTestOptions({ title: 'Test', markdown: { processedDirs } }); + + return getMarkdownProcessorPaths({ ...options, astroConfig: { root, srcDir } }); +} diff --git a/packages/starlight/integrations/markdown-process.ts b/packages/starlight/integrations/markdown-process.ts index 7ba9815e118..0b99c8cf0fc 100644 --- a/packages/starlight/integrations/markdown-process.ts +++ b/packages/starlight/integrations/markdown-process.ts @@ -2,6 +2,7 @@ import { resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import type { AstroConfig } from 'astro'; import { resolveCollectionPath } from '../utils/collection-fs'; +import { ensureTrailingSlash } from '../utils/path'; import type { HookParameters, StarlightConfig } from '../types'; /** @@ -21,10 +22,12 @@ export interface MarkdownProcessorPluginOptions { * utility to determine if a file should be transformed by a plugin or not. */ export function getMarkdownProcessorPaths(options: MarkdownProcessorPluginOptions): string[] { - const paths = [normalizePath(resolveCollectionPath('docs', options.astroConfig.srcDir))]; + const paths = [normalizeDirectoryPath(resolveCollectionPath('docs', options.astroConfig.srcDir))]; for (const processedDir of options.starlightConfig.markdown.processedDirs) { - paths.push(normalizePath(resolve(fileURLToPath(options.astroConfig.root), processedDir))); + paths.push( + normalizeDirectoryPath(resolve(fileURLToPath(options.astroConfig.root), processedDir)) + ); } return paths; @@ -50,3 +53,12 @@ const backSlashRegex = /\\/g; function normalizePath(path: string) { return path.replace(backSlashRegex, '/'); } + +/** + * Allowed paths are directory prefixes compared with `startsWith()` in {@link shouldTransformPath}, + * so we ensure they have a trailing slash to avoid matching sibling directories with the same + * prefix. + */ +function normalizeDirectoryPath(path: string) { + return ensureTrailingSlash(normalizePath(path)); +}