From 9579ac10fca5c5dfd72de84e1c5fb668ba157da2 Mon Sep 17 00:00:00 2001 From: slorber Date: Mon, 25 May 2020 18:21:41 +0200 Subject: [PATCH] split collectRedirects and writeRedirectFiles in separate files --- .../src/collectRedirects.ts | 89 +++++++++++++ .../src/index.ts | 126 ++---------------- .../src/types.ts | 18 +++ .../src/writeRedirectFiles.ts | 28 ++++ 4 files changed, 146 insertions(+), 115 deletions(-) create mode 100644 packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts create mode 100644 packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts diff --git a/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts b/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts new file mode 100644 index 0000000000..2b862e3564 --- /dev/null +++ b/packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts @@ -0,0 +1,89 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import {flatten} from 'lodash'; +import { + RedirectsCreator, + PluginContext, + RedirectMetadata, + PluginOptions, +} from './types'; +import createRedirectPageContent from './createRedirectPageContent'; +import {addTrailingSlash, getFilePathForRoutePath} from './utils'; +import { + fromExtensionsRedirectCreator, + toExtensionsRedirectCreator, +} from './redirectCreators'; + +export default function collectRedirects( + pluginContext: PluginContext, +): RedirectMetadata[] { + const redirectsCreators: RedirectsCreator[] = buildRedirectCreators( + pluginContext.options, + ); + + return flatten( + redirectsCreators.map((redirectCreator) => { + return createRoutesPathsRedirects(redirectCreator, pluginContext); + }), + ); +} + +function buildRedirectCreators(options: PluginOptions): RedirectsCreator[] { + const noopRedirectCreator: RedirectsCreator = (_routePath: string) => []; + return [ + fromExtensionsRedirectCreator(options.fromExtensions), + toExtensionsRedirectCreator(options.toExtensions), + options.createRedirects ?? noopRedirectCreator, + ]; +} + +// Create all redirects for a list of route path +function createRoutesPathsRedirects( + redirectCreator: RedirectsCreator, + pluginContext: PluginContext, +): RedirectMetadata[] { + return flatten( + pluginContext.routesPaths.map((routePath) => + createRoutePathRedirects(routePath, redirectCreator, pluginContext), + ), + ); +} + +// Create all redirects for a single route path +function createRoutePathRedirects( + routePath: string, + redirectCreator: RedirectsCreator, + {siteConfig, outDir}: PluginContext, +): RedirectMetadata[] { + // TODO do we receive absolute urls??? + if (!path.isAbsolute(routePath)) { + return []; + } + + // TODO addTrailingSlash ? + const toUrl = addTrailingSlash(`${siteConfig.url}${routePath}`); + + const redirectPageContent = createRedirectPageContent({toUrl}); + + const fromRoutePaths: string[] = redirectCreator(routePath) ?? []; + + return fromRoutePaths.map((fromRoutePath) => { + const redirectAbsoluteFilePath = path.join( + outDir, + getFilePathForRoutePath(fromRoutePath), + ); + return { + fromRoutePath, + toRoutePath: routePath, + toUrl, + redirectPageContent, + redirectAbsoluteFilePath, + }; + }); +} diff --git a/packages/docusaurus-plugin-client-redirects/src/index.ts b/packages/docusaurus-plugin-client-redirects/src/index.ts index 59037874fc..2016fbe397 100644 --- a/packages/docusaurus-plugin-client-redirects/src/index.ts +++ b/packages/docusaurus-plugin-client-redirects/src/index.ts @@ -5,137 +5,33 @@ * LICENSE file in the root directory of this source tree. */ -import fs from 'fs-extra'; -import path from 'path'; -import {flatten} from 'lodash'; - import {LoadContext, Plugin, Props} from '@docusaurus/types'; +import {UserPluginOptions, PluginContext, RedirectMetadata} from './types'; -import {PluginOptions, UserPluginOptions, RedirectsCreator} from './types'; -import createRedirectPageContent from './createRedirectPageContent'; import normalizePluginOptions from './normalizePluginOptions'; -import {addTrailingSlash, getFilePathForRoutePath} from './utils'; -import { - fromExtensionsRedirectCreator, - toExtensionsRedirectCreator, -} from './redirectCreators'; - -type RedirectMetadata = { - fromRoutePath: string; - toRoutePath: string; - toUrl: string; - redirectPageContent: string; - redirectAbsoluteFilePath: string; -}; - -type PluginContext = { - props: Props; - options: PluginOptions; - redirectsCreators: RedirectsCreator[]; -}; +import collectRedirects from './collectRedirects'; +import writeRedirectFiles from './writeRedirectFiles'; export default function pluginClientRedirectsPages( _context: LoadContext, opts: UserPluginOptions, ): Plugin { const options = normalizePluginOptions(opts); + return { name: 'docusaurus-plugin-client-redirects', async postBuild(props: Props) { - const redirectsCreators: RedirectsCreator[] = buildRedirectCreators( + const pluginContext: PluginContext = { + routesPaths: props.routesPaths, + siteConfig: props.siteConfig, + outDir: props.outDir, options, - ); + }; - const pluginContext: PluginContext = {props, options, redirectsCreators}; - - // Process in 2 steps, to make code more easy to test - const redirects: RedirectMetadata[] = collectRoutePathRedirects( - pluginContext, - ); - - console.log('redirects=', redirects); + const redirects: RedirectMetadata[] = collectRedirects(pluginContext); + // Write files only at the end: make code more easy to test without IO await writeRedirectFiles(redirects); }, }; } - -function buildRedirectCreators(options: PluginOptions): RedirectsCreator[] { - const noopRedirectCreator: RedirectsCreator = (_routePath: string) => []; - return [ - fromExtensionsRedirectCreator(options.fromExtensions), - toExtensionsRedirectCreator(options.toExtensions), - options.createRedirects ?? noopRedirectCreator, - ]; -} - -function collectRoutePathRedirects( - pluginContext: PluginContext, -): RedirectMetadata[] { - return flatten( - pluginContext.redirectsCreators.map((redirectCreator) => { - return createRoutesPathsRedirects(redirectCreator, pluginContext); - }), - ); -} - -// Create all redirects for a list of route path -function createRoutesPathsRedirects( - redirectCreator: RedirectsCreator, - pluginContext: PluginContext, -): RedirectMetadata[] { - return flatten( - pluginContext.props.routesPaths.map((routePath) => - createRoutePathRedirects(routePath, redirectCreator, pluginContext), - ), - ); -} - -// Create all redirects for a single route path -function createRoutePathRedirects( - routePath: string, - redirectCreator: RedirectsCreator, - {props}: PluginContext, -): RedirectMetadata[] { - const {siteConfig, outDir} = props; - - // TODO do we receive absolute urls??? - if (!path.isAbsolute(routePath)) { - return []; - } - - // TODO addTrailingSlash ? - const toUrl = addTrailingSlash(`${siteConfig.url}${routePath}`); - - const redirectPageContent = createRedirectPageContent({toUrl}); - - const fromRoutePaths: string[] = redirectCreator(routePath) ?? []; - - return fromRoutePaths.map((fromRoutePath) => { - const redirectAbsoluteFilePath = path.join( - outDir, - getFilePathForRoutePath(fromRoutePath), - ); - return { - fromRoutePath, - toRoutePath: routePath, - toUrl, - redirectPageContent, - redirectAbsoluteFilePath, - }; - }); -} - -async function writeRedirectFiles(redirects: RedirectMetadata[]) { - async function writeRedirectFile(redirect: RedirectMetadata) { - try { - await fs.writeFile( - redirect.redirectAbsoluteFilePath, - redirect.redirectPageContent, - ); - } catch (err) { - throw new Error(`Redirect file creation error: ${err}`); - } - } - await Promise.all(redirects.map(writeRedirectFile)); -} diff --git a/packages/docusaurus-plugin-client-redirects/src/types.ts b/packages/docusaurus-plugin-client-redirects/src/types.ts index b993558ef9..b5b542484a 100644 --- a/packages/docusaurus-plugin-client-redirects/src/types.ts +++ b/packages/docusaurus-plugin-client-redirects/src/types.ts @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +import {Props} from '@docusaurus/types'; + export type PluginOptions = { fromExtensions: string[]; toExtensions: string[]; @@ -18,3 +20,19 @@ export type UserPluginOptions = Partial; export type RedirectsCreator = ( routePath: string, ) => string[] | null | undefined; + +// Having an in-memory representation of wanted redirects is easier to test +export type RedirectMetadata = { + fromRoutePath: string; + toRoutePath: string; + toUrl: string; + redirectPageContent: string; + redirectAbsoluteFilePath: string; +}; + +export type PluginContext = Pick< + Props, + 'routesPaths' | 'siteConfig' | 'outDir' +> & { + options: PluginOptions; +}; diff --git a/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts b/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts new file mode 100644 index 0000000000..7dbda45323 --- /dev/null +++ b/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import fs from 'fs-extra'; +import {RedirectMetadata} from './types'; + +type RedirectFile = Pick< + RedirectMetadata, + 'redirectAbsoluteFilePath' | 'redirectPageContent' +>; + +export default async function writeRedirectFiles(redirects: RedirectFile[]) { + async function writeRedirectFile(redirect: RedirectFile) { + try { + await fs.writeFile( + redirect.redirectAbsoluteFilePath, + redirect.redirectPageContent, + ); + } catch (err) { + throw new Error(`Redirect file creation error: ${err}`); + } + } + await Promise.all(redirects.map(writeRedirectFile)); +}