From c8d48052b5f12be927599ad0b00bd0977e6fbb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Doreau?= <32459935+ayshiff@users.noreply.github.com> Date: Tue, 29 Sep 2020 17:09:26 +0200 Subject: [PATCH] fix(v2): normalizeUrl edge cases (#3427) * fix(utils): cover normalizeUrl edge cases * fix(utils): normalizeUrl new edge cases --- .../src/__tests__/index.test.ts | 44 +++++++++++++++++++ packages/docusaurus-utils/src/index.ts | 28 +++++++++--- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-utils/src/__tests__/index.test.ts b/packages/docusaurus-utils/src/__tests__/index.test.ts index 9a14101a53..44411a921a 100644 --- a/packages/docusaurus-utils/src/__tests__/index.test.ts +++ b/packages/docusaurus-utils/src/__tests__/index.test.ts @@ -258,6 +258,22 @@ describe('load utils', () => { test('normalizeUrl', () => { const asserts = [ + { + input: ['/', ''], + output: '/', + }, + { + input: ['', '/'], + output: '/', + }, + { + input: ['/'], + output: '/', + }, + { + input: [''], + output: '', + }, { input: ['/', '/'], output: '/', @@ -306,6 +322,34 @@ describe('load utils', () => { input: ['http://foobar.com', '', 'test', '/'], output: 'http://foobar.com/test/', }, + { + input: ['/', '', 'hello', '', '/', '/', '', '/', '/world'], + output: '/hello/world', + }, + { + input: ['', '', '/tt', 'ko', 'hello'], + output: '/tt/ko/hello', + }, + { + input: ['', '///hello///', '', '///world'], + output: '/hello/world', + }, + { + input: ['', '/hello/', ''], + output: '/hello/', + }, + { + input: ['', '/', ''], + output: '/', + }, + { + input: ['///', '///'], + output: '/', + }, + { + input: ['/', '/hello/world/', '///'], + output: '/hello/world/', + }, ]; asserts.forEach((testCase) => { expect(normalizeUrl(testCase.input)).toBe(testCase.output); diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 6b85cd1408..21c8488dee 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -282,6 +282,9 @@ export function normalizeUrl(rawUrls: string[]): string { const urls = rawUrls; const resultArray = []; + let hasStartingSlash = false; + let hasEndingSlash = false; + // If the first part is a plain protocol, we combine it with the next part. if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) { const first = urls.shift(); @@ -302,19 +305,30 @@ export function normalizeUrl(rawUrls: string[]): string { } if (component === '') { + if (i === urls.length - 1 && hasEndingSlash) { + resultArray.push('/'); + } // eslint-disable-next-line continue; } - if (i > 0) { - // Removing the starting slashes for each component but the first. - component = component.replace(/^[/]+/, ''); + if (component !== '/') { + if (i > 0) { + // Removing the starting slashes for each component but the first. + component = component.replace( + /^[/]+/, + // Special case where the first element of rawUrls is empty ["", "/hello"] => /hello + component[0] === '/' && !hasStartingSlash ? '/' : '', + ); + } + + hasEndingSlash = component[component.length - 1] === '/'; + // Removing the ending slashes for each component but the last. + // For the last component we will combine multiple slashes to a single one. + component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/'); } - // Removing the ending slashes for each component but the last. - // For the last component we will combine multiple slashes to a single one. - component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/'); - + hasStartingSlash = true; resultArray.push(component); }