diff --git a/src/utilities/process-readme.mjs b/src/utilities/process-readme.mjs index f3aa7f15bd57..9943e2df69fa 100644 --- a/src/utilities/process-readme.mjs +++ b/src/utilities/process-readme.mjs @@ -24,6 +24,23 @@ const fragmentLinkMap = { "/guides/shimming/#provideplugin": "/plugins/provide-plugin/", }; +/** + * The page a raw README url is rendered at. A raw url names the branch where a + * rendered one names `blob` and then the branch, and the branch is whatever the + * repository calls its default one. + * @param {string} sourceUrl where the readme was read from + * @returns {string} what its relative links resolve against + */ +function renderedUrlOf(sourceUrl) { + const raw = new URL(sourceUrl); + + if (raw.hostname !== "raw.githubusercontent.com") return sourceUrl; + + const [, owner, repository, ...rest] = raw.pathname.split("/"); + + return `https://github.com/${owner}/${repository}/blob/${rest.join("/")}`; +} + function linkFixerFactory(sourceUrl) { return function linkFixer(markdownLink, href) { const oldHref = href; @@ -34,12 +51,7 @@ function linkFixerFactory(sourceUrl) { // Only resolve non-absolute urls from their source if they are not a document fragment link if (!href.startsWith("#")) { - // Convert Github raw links to rendered links - const renderedUrl = sourceUrl - .replace(/raw.githubusercontent.com/, "github.com") - .replace(/master/, "blob/master"); - - href = new URL(href, renderedUrl).href; + href = new URL(href, renderedUrlOf(sourceUrl)).href; } // Modify absolute documentation links to be root relative diff --git a/src/utilities/process-readme.test.mjs b/src/utilities/process-readme.test.mjs index 5c0878fb1478..21c0bae88a04 100644 --- a/src/utilities/process-readme.test.mjs +++ b/src/utilities/process-readme.test.mjs @@ -18,6 +18,20 @@ describe("processReadme", () => { ); }); + it("renders a relative link against the branch the readme was read from", () => { + // A raw url names the branch where a rendered one names `blob` and then + // the branch, whatever the repository calls its default one. + for (const branch of ["master", "main", "next"]) { + const options = { + source: `https://raw.githubusercontent.com/webpack/html-loader/${branch}/README.md`, + }; + + expect(processReadme("[LICENSE](./LICENSE)", options)).toBe( + `[LICENSE](https://github.com/webpack/html-loader/blob/${branch}/LICENSE)`, + ); + } + }); + it("keeps the github link when the site builds no page for the package", () => { const options = { source: url, @@ -80,7 +94,7 @@ describe("processReadme", () => { const loaderMDData = "See the file [`./src/config.d.ts`](./src/config.d.ts)."; expect(processReadme(loaderMDData, options)).toBe( - "See the file [`https://github.com/webpack/postcss-loader/main/src/config.d.ts`](https://github.com/webpack/postcss-loader/main/src/config.d.ts).", + "See the file [`https://github.com/webpack/postcss-loader/blob/main/src/config.d.ts`](https://github.com/webpack/postcss-loader/blob/main/src/config.d.ts).", ); });