From 276717059b048580e1f5c909418baf603f748065 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Thu, 8 Sep 2022 00:22:53 -0400 Subject: [PATCH] fix(redirect): tolerate trailing slash difference if config is undefined --- .../collectRedirects.test.ts.snap | 21 ++++++- .../src/__tests__/collectRedirects.test.ts | 63 +++++++++++++++++++ .../src/collectRedirects.ts | 58 ++++++++++++++--- 3 files changed, 133 insertions(+), 9 deletions(-) diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap index a9ce789f9861..25887592b6a4 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap @@ -1,8 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`collectRedirects throw if plugin option redirects contain invalid to paths 1`] = ` -"You are trying to create client-side redirections to paths that do not exist: -- /this/path/does/not/exist2 +"You are trying to create client-side redirections to invalid paths. + +These paths are redirected to but do not exist: - /this/path/does/not/exist2 Valid paths you can redirect to: @@ -12,6 +13,22 @@ Valid paths you can redirect to: " `; +exports[`collectRedirects throw if plugin option redirects contain to paths with mismatching trailing slash 1`] = ` +"You are trying to create client-side redirections to invalid paths. + +These paths do exist, but because you have explicitly set trailingSlash=false, you need to write the path without trailing slash: +- /someExistingPath/ +" +`; + +exports[`collectRedirects throw if plugin option redirects contain to paths with mismatching trailing slash 2`] = ` +"You are trying to create client-side redirections to invalid paths. + +These paths do exist, but because you have explicitly set trailingSlash=true, you need to write the path with trailing slash: +- /someExistingPath +" +`; + exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = ` "Some created redirects are invalid: - {"from":["/fromPath"],"to":"/"} => Validation error: "from" must be a string diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts index e9a200c98943..021eba260387 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts @@ -220,6 +220,69 @@ describe('collectRedirects', () => { ).toThrowErrorMatchingSnapshot(); }); + it('tolerates mismatched trailing slash if option is undefined', () => { + expect( + collectRedirects( + createTestPluginContext( + { + redirects: [ + { + from: '/someLegacyPath', + to: '/somePath', + }, + ], + }, + ['/', '/somePath/'], + {trailingSlash: undefined}, + ), + undefined, + ), + ).toEqual([ + { + from: '/someLegacyPath', + to: '/somePath', + }, + ]); + }); + + it('throw if plugin option redirects contain to paths with mismatching trailing slash', () => { + expect(() => + collectRedirects( + createTestPluginContext( + { + redirects: [ + { + from: '/someLegacyPath', + to: '/someExistingPath/', + }, + ], + }, + ['/', '/someExistingPath', '/anotherExistingPath'], + {trailingSlash: false}, + ), + undefined, + ), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + collectRedirects( + createTestPluginContext( + { + redirects: [ + { + from: '/someLegacyPath', + to: '/someExistingPath', + }, + ], + }, + ['/', '/someExistingPath/', '/anotherExistingPath/'], + {trailingSlash: true}, + ), + undefined, + ), + ).toThrowErrorMatchingSnapshot(); + }); + it('collects redirects with custom redirect creator', () => { expect( collectRedirects( diff --git a/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts b/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts index 605a2b4af75f..666c51e433ab 100644 --- a/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts +++ b/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts @@ -7,6 +7,7 @@ import _ from 'lodash'; import logger from '@docusaurus/logger'; +import {addTrailingSlash, removeTrailingSlash} from '@docusaurus/utils'; import {applyTrailingSlash} from '@docusaurus/utils-common'; import { createFromExtensionsRedirects, @@ -80,16 +81,59 @@ function validateCollectedRedirects( const allowedToPaths = pluginContext.relativeRoutesPaths; const toPaths = redirects.map((redirect) => redirect.to); - const illegalToPaths = _.difference(toPaths, allowedToPaths); - if (illegalToPaths.length > 0) { - throw new Error( - `You are trying to create client-side redirections to paths that do not exist: -- ${illegalToPaths.join('\n- ')} + const trailingSlashConfig = pluginContext.siteConfig.trailingSlash; + // Key is the path, value is whether a valid toPath with a different trailing + // slash exists; if the key doesn't exist it means it's valid + const differByTrailSlash = new Map(toPaths.map((path) => [path, false])); + allowedToPaths.forEach((toPath) => { + if (differByTrailSlash.has(toPath)) { + differByTrailSlash.delete(toPath); + } else if (differByTrailSlash.has(removeTrailingSlash(toPath))) { + if (trailingSlashConfig === true) { + differByTrailSlash.set(removeTrailingSlash(toPath), true); + } else { + differByTrailSlash.delete(removeTrailingSlash(toPath)); + } + } else if (differByTrailSlash.has(addTrailingSlash(toPath))) { + if (trailingSlashConfig === false) { + differByTrailSlash.set(addTrailingSlash(toPath), true); + } else { + differByTrailSlash.delete(addTrailingSlash(toPath)); + } + } + }); + if (differByTrailSlash.size > 0) { + console.log(differByTrailSlash); + const errors = Array.from(differByTrailSlash.entries()); + + let message = + 'You are trying to create client-side redirections to invalid paths.\n'; + + const [trailingSlashIssues, invalidPaths] = _.partition( + errors, + ([, differ]) => differ, + ); + + if (trailingSlashIssues.length) { + message += ` +These paths do exist, but because you have explicitly set trailingSlash=${trailingSlashConfig}, you need to write the path ${ + trailingSlashConfig ? 'with trailing slash' : 'without trailing slash' + }: +- ${trailingSlashIssues.map(([p]) => p).join('\n- ')} +`; + } + + if (invalidPaths.length) { + message += ` +These paths are redirected to but do not exist: +- ${invalidPaths.map(([p]) => p).join('\n- ')} Valid paths you can redirect to: - ${allowedToPaths.join('\n- ')} -`, - ); +`; + } + + throw new Error(message); } }