From 8c30babc8e493a9755f807d8453ce27314ddc5f1 Mon Sep 17 00:00:00 2001 From: Kiran Teja Date: Tue, 11 Aug 2026 11:27:39 +0530 Subject: [PATCH 1/3] fix html permalink output path --- .../src/__tests__/emitUtils.test.ts | 9 +++++++ packages/docusaurus-utils/src/emitUtils.ts | 27 +++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index 0d6e700721f4..9fa4b21a57f7 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -89,6 +89,15 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toBe('htmlFile.html\n'); }); + it('reads file ending in .html with trailing slash true', async () => { + await expect( + readOutputHTMLFile( + '/htmlFile.html', + path.join(__dirname, '__fixtures__/build-snap'), + true, + ).then(String), + ).resolves.toBe('htmlFile.html\n'); + }); it('reads file ending in .html in folder containing .html', async () => { await expect( readOutputHTMLFile( diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts index 239569defb01..ca01be833065 100644 --- a/packages/docusaurus-utils/src/emitUtils.ts +++ b/packages/docusaurus-utils/src/emitUtils.ts @@ -82,23 +82,28 @@ export async function readOutputHTMLFile( outDir: string, trailingSlash: boolean | undefined, ): Promise { - const withTrailingSlashPath = path.join(outDir, permalink, 'index.html'); - const withoutTrailingSlashPath = (() => { - const basePath = path.join(outDir, permalink.replace(/\/$/, '')); - const htmlSuffix = /\.html?$/i.test(basePath) ? '' : '.html'; - return `${basePath}${htmlSuffix}`; - })(); + const normalizedPermalink = permalink.replace(/\/$/, ''); + const withTrailingSlashPath = path.join( + outDir, + normalizedPermalink, + 'index.html', + ); + const withoutTrailingSlashPath = path.join(outDir, normalizedPermalink); + const isHtmlPath = /\.html?$/i.test(normalizedPermalink); - const possibleHtmlPaths = [ - trailingSlash !== false && withTrailingSlashPath, - trailingSlash !== true && withoutTrailingSlashPath, - ].filter((p): p is string => Boolean(p)); + const possibleHtmlPaths = isHtmlPath + ? [withoutTrailingSlashPath] + : trailingSlash === true + ? [withTrailingSlashPath] + : trailingSlash === false + ? [`${withoutTrailingSlashPath}.html`] + : [withTrailingSlashPath, `${withoutTrailingSlashPath}.html`]; const HTMLPath = await findAsyncSequential(possibleHtmlPaths, fs.pathExists); if (!HTMLPath) { throw new Error( - `Expected output HTML file to be found at ${withTrailingSlashPath} for permalink ${permalink}.`, + `Expected output HTML file to be found at ${possibleHtmlPaths[0]} for permalink ${permalink}.`, ); } return fs.readFile(HTMLPath); From df293f447ce6fe4f9b22dd9363609605c79ab579 Mon Sep 17 00:00:00 2001 From: Kiran Teja Date: Tue, 11 Aug 2026 11:42:10 +0530 Subject: [PATCH 2/3] chore: rerun checks From fdc8b311c1dc529c088c7d4375b487eda2f948ee Mon Sep 17 00:00:00 2001 From: Kiran Teja Date: Tue, 11 Aug 2026 12:01:21 +0530 Subject: [PATCH 3/3] fix blog feed html path fallback --- .../src/__tests__/emitUtils.test.ts | 15 ++++++++ packages/docusaurus-utils/src/emitUtils.ts | 35 +++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index 9fa4b21a57f7..d8a5c2f137b2 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -7,6 +7,7 @@ import {describe, expect, it, vi} from 'vitest'; import path from 'path'; +import os from 'os'; import fs from 'fs-extra'; import {readOutputHTMLFile, generate} from '../emitUtils'; @@ -114,6 +115,20 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toBe('nestedHtmlFile.html\n'); }); + it('reads index.html when the permalink path is a directory', async () => { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'docusaurus-')); + try { + const dirPath = path.join(tempDir, 'dir.html'); + await fs.ensureDir(dirPath); + await fs.writeFile(path.join(dirPath, 'index.html'), 'dir-index\n'); + + await expect( + readOutputHTMLFile('/dir.html', tempDir, undefined).then(String), + ).resolves.toBe('dir-index\n'); + } finally { + await fs.remove(tempDir); + } + }); // Can it ever happen? it('throws if file does not exist', async () => { await expect( diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts index ca01be833065..5db2904b9176 100644 --- a/packages/docusaurus-utils/src/emitUtils.ts +++ b/packages/docusaurus-utils/src/emitUtils.ts @@ -99,12 +99,43 @@ export async function readOutputHTMLFile( ? [`${withoutTrailingSlashPath}.html`] : [withTrailingSlashPath, `${withoutTrailingSlashPath}.html`]; - const HTMLPath = await findAsyncSequential(possibleHtmlPaths, fs.pathExists); + async function readCandidateHTMLFile( + candidatePath: string, + ): Promise { + if (!(await fs.pathExists(candidatePath))) { + return null; + } + try { + return await fs.readFile(candidatePath); + } catch (error) { + if ((error as NodeJS.ErrnoException)?.code !== 'EISDIR') { + throw error; + } + } + + const candidateIndexPath = path.join(candidatePath, 'index.html'); + if (await fs.pathExists(candidateIndexPath)) { + return fs.readFile(candidateIndexPath); + } + + return null; + } + + const HTMLPath = await findAsyncSequential(possibleHtmlPaths, async (p) => + Boolean(await readCandidateHTMLFile(p)), + ); if (!HTMLPath) { throw new Error( `Expected output HTML file to be found at ${possibleHtmlPaths[0]} for permalink ${permalink}.`, ); } - return fs.readFile(HTMLPath); + + const content = await readCandidateHTMLFile(HTMLPath); + if (!content) { + throw new Error( + `Expected output HTML file to be found at ${HTMLPath} for permalink ${permalink}.`, + ); + } + return content; }