diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/routes.test.ts.snap index d3c2c42d09bf..d7a20602dd42 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/routes.test.ts.snap @@ -399,7 +399,7 @@ exports[`buildAllRoutes works for realistic blog post 2`] = ` "listMetadata": { "blogDescription": "Custom blog description", "blogTitle": "Custom blog title", - "nextPage": "/blog/authors/author1/authors/2", + "nextPage": "/blog/authors/author1/page/2", "page": 1, "permalink": "/blog/authors/author1", "postsPerPage": 2, @@ -429,7 +429,7 @@ exports[`buildAllRoutes works for realistic blog post 2`] = ` ], "sidebar": "@aliased/data/blog-post-list-prop-default.json", }, - "path": "/blog/authors/author1/authors/2", + "path": "/blog/authors/author1/page/2", "props": { "author": { "count": 3, @@ -444,7 +444,7 @@ exports[`buildAllRoutes works for realistic blog post 2`] = ` "blogTitle": "Custom blog title", "nextPage": undefined, "page": 2, - "permalink": "/blog/authors/author1/authors/2", + "permalink": "/blog/authors/author1/page/2", "postsPerPage": 2, "previousPage": "/blog/authors/author1", "totalCount": 3, diff --git a/packages/docusaurus-plugin-content-blog/src/routes.ts b/packages/docusaurus-plugin-content-blog/src/routes.ts index 55bb98212e73..b8667d3dd224 100644 --- a/packages/docusaurus-plugin-content-blog/src/routes.ts +++ b/packages/docusaurus-plugin-content-blog/src/routes.ts @@ -327,7 +327,7 @@ export async function buildAllRoutes({ basePageUrl: author.page.permalink, blogDescription, blogTitle, - pageBasePath: authorsBasePath, + pageBasePath, postsPerPageOption: postsPerPage, }); diff --git a/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts b/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts index a91476457447..544bc5889332 100644 --- a/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts +++ b/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts @@ -28,7 +28,7 @@ describe('isInternalUrl', () => { expect(isInternalUrl('https://foo.com')).toBeFalsy(); }); - it('returns false for whatever protocol links', () => { + it('returns false for relative protocol links', () => { expect(isInternalUrl('//foo.com')).toBeFalsy(); }); @@ -43,4 +43,50 @@ describe('isInternalUrl', () => { it('returns false for undefined links', () => { expect(isInternalUrl(undefined)).toBeFalsy(); }); + + describe('custom scheme links', () => { + it('returns true for invalid protocol schemes', () => { + expect(isInternalUrl('+customScheme://')).toBeTruthy(); + expect(isInternalUrl('+customScheme://whatever')).toBeTruthy(); + expect(isInternalUrl('+customScheme:whatever')).toBeTruthy(); + + expect(isInternalUrl('.customScheme://')).toBeTruthy(); + expect(isInternalUrl('.customScheme://whatever')).toBeTruthy(); + expect(isInternalUrl('.customScheme:whatever')).toBeTruthy(); + + expect(isInternalUrl('-customScheme://')).toBeTruthy(); + expect(isInternalUrl('-customScheme://whatever')).toBeTruthy(); + expect(isInternalUrl('-customScheme:whatever')).toBeTruthy(); + + expect(isInternalUrl('custom_scheme://')).toBeTruthy(); + expect(isInternalUrl('custom_scheme://whatever')).toBeTruthy(); + expect(isInternalUrl('custom_scheme:whatever')).toBeTruthy(); + + expect(isInternalUrl('custom scheme://')).toBeTruthy(); + expect(isInternalUrl('custom scheme://whatever')).toBeTruthy(); + expect(isInternalUrl('custom scheme:whatever')).toBeTruthy(); + + expect(isInternalUrl('custom$scheme://')).toBeTruthy(); + expect(isInternalUrl('custom$scheme://whatever')).toBeTruthy(); + expect(isInternalUrl('custom$scheme:whatever')).toBeTruthy(); + }); + + it('returns false valid protocol schemes', () => { + expect(isInternalUrl('customScheme://')).toBeFalsy(); + expect(isInternalUrl('customScheme://whatever')).toBeFalsy(); + expect(isInternalUrl('customScheme:whatever')).toBeFalsy(); + + expect(isInternalUrl('custom-scheme://')).toBeFalsy(); + expect(isInternalUrl('custom-scheme://whatever')).toBeFalsy(); + expect(isInternalUrl('custom-scheme:whatever')).toBeFalsy(); + + expect(isInternalUrl('custom.scheme://')).toBeFalsy(); + expect(isInternalUrl('custom.scheme://whatever')).toBeFalsy(); + expect(isInternalUrl('custom.scheme:whatever')).toBeFalsy(); + + expect(isInternalUrl('custom-sch.eme+-.://')).toBeFalsy(); + expect(isInternalUrl('custom-sch.eme+-.://whatever')).toBeFalsy(); + expect(isInternalUrl('custom-sch.eme+-.:whatever')).toBeFalsy(); + }); + }); }); diff --git a/packages/docusaurus/src/client/exports/isInternalUrl.ts b/packages/docusaurus/src/client/exports/isInternalUrl.ts index 489aff74bc0d..6335ae003e61 100644 --- a/packages/docusaurus/src/client/exports/isInternalUrl.ts +++ b/packages/docusaurus/src/client/exports/isInternalUrl.ts @@ -5,8 +5,11 @@ * LICENSE file in the root directory of this source tree. */ +// Poor man's protocol detection +// Spec: https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 +// In particular: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) export function hasProtocol(url: string): boolean { - return /^(?:\w*:|\/\/)/.test(url); + return /^(?:[A-Za-z][A-Za-z\d+.-]*:|\/\/)/.test(url); } export default function isInternalUrl(url?: string): boolean { diff --git a/website/_dogfooding/_pages tests/markdown-tests-mdx.mdx b/website/_dogfooding/_pages tests/markdown-tests-mdx.mdx index ec3a7534af01..55153cd3ca1a 100644 --- a/website/_dogfooding/_pages tests/markdown-tests-mdx.mdx +++ b/website/_dogfooding/_pages tests/markdown-tests-mdx.mdx @@ -360,15 +360,10 @@ This is a test page to see if Docusaurus Markdown features are working properly See [#3337](https://github.com/facebook/docusaurus/issues/3337) - [/someFile.pdf](/someFile.pdf) - - [/someFile.xyz](/someFile.xyz) - - [/image with space.png]() - - [@site/\_dogfooding/\_asset-tests/someFile.pdf](@site/_dogfooding/_asset-tests/someFile.pdf) - - [@site/\_dogfooding/\_asset-tests/someFile.xyz](@site/_dogfooding/_asset-tests/someFile.xyz) - - [@site/\_dogfooding/\_asset-tests/image with space.png](<@site/_dogfooding/_asset-tests/image with spaces.png>) ### Linking to non-SPA page hosted within website @@ -376,13 +371,16 @@ See [#3337](https://github.com/facebook/docusaurus/issues/3337) See [#3309](https://github.com/facebook/docusaurus/issues/3309) - [pathname:///dogfooding/javadoc](pathname:///dogfooding/javadoc) - - [pathname:///dogfooding/javadoc/index.html](pathname:///dogfooding/javadoc/index.html) - - [pathname://../dogfooding/javadoc](pathname://../dogfooding/javadoc) - - [pathname://../dogfooding/javadoc/index.html](pathname://../dogfooding/javadoc/index.html) +### Linking to non-SPA paths with custom schemes + +- [customScheme://whatever](customScheme://whatever) +- [custom-scheme://whatever](custom-scheme://whatever) +- [custom-sch.eme+-.://whatever](custom-sch.eme+-.://whatever) + ### Linking to non-SPA page with Link component See [#9758](https://github.com/facebook/docusaurus/issues/9758), these external urls should not be reported by the broken links checker: