diff --git a/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts b/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts index a914764574..544bc58893 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 489aff74bc..6335ae003e 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 ec3a7534af..55153cd3ca 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: