Skip to content

Commit

Permalink
refactor(client-redirects): migrate validation to validateOptions lif…
Browse files Browse the repository at this point in the history
…ecycle (#6924)
  • Loading branch information
Josh-Cena committed Mar 16, 2022
1 parent 68aaf92 commit da9f38b
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 113 deletions.
4 changes: 3 additions & 1 deletion packages/docusaurus-module-type-aliases/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ declare module '@docusaurus/Link' {
readonly href?: string;
readonly autoAddBaseUrl?: boolean;

// escape hatch in case broken links check is annoying for a specific link
/**
* escape hatch in case broken links check is annoying for a specific link
*/
readonly 'data-noBrokenLinkCheck'?: boolean;
};
export default function Link(props: Props): JSX.Element;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`normalizePluginOptions rejects bad createRedirects user inputs 1`] = `"\\"createRedirects\\" must be of type function"`;

exports[`normalizePluginOptions rejects bad fromExtensions user inputs 1`] = `"\\"fromExtensions[0]\\" contains an invalid value"`;

exports[`normalizePluginOptions rejects bad toExtensions user inputs 1`] = `"\\"toExtensions[0]\\" contains an invalid value"`;
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@

import type {PluginContext} from '../types';
import collectRedirects from '../collectRedirects';
import normalizePluginOptions from '../normalizePluginOptions';
import {validateOptions} from '../options';
import {removeTrailingSlash} from '@docusaurus/utils';
import {normalizePluginOptions} from '@docusaurus/utils-validation';
import type {Options} from '@docusaurus/plugin-client-redirects';

function createTestPluginContext(
Expand All @@ -19,7 +20,7 @@ function createTestPluginContext(
outDir: '/tmp',
baseUrl: 'https://docusaurus.io',
relativeRoutesPaths,
options: normalizePluginOptions(options),
options: validateOptions({validate: normalizePluginOptions, options}),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,38 @@
* LICENSE file in the root directory of this source tree.
*/

import normalizePluginOptions, {
DefaultPluginOptions,
} from '../normalizePluginOptions';
import type {CreateRedirectsFnOption} from '@docusaurus/plugin-client-redirects';
import {validateOptions, DEFAULT_OPTIONS} from '../options';
import {normalizePluginOptions} from '@docusaurus/utils-validation';
import type {
CreateRedirectsFnOption,
Options,
} from '@docusaurus/plugin-client-redirects';

function testValidate(options: Options) {
return validateOptions({validate: normalizePluginOptions, options});
}

describe('normalizePluginOptions', () => {
it('returns default options for undefined user options', () => {
expect(normalizePluginOptions()).toEqual(DefaultPluginOptions);
expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS);
});

it('returns default options for empty user options', () => {
expect(normalizePluginOptions()).toEqual(DefaultPluginOptions);
expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS);
});

it('overrides one default options with valid user options', () => {
expect(
normalizePluginOptions({
testValidate({
toExtensions: ['html'],
}),
).toEqual({...DefaultPluginOptions, toExtensions: ['html']});
).toEqual({...DEFAULT_OPTIONS, id: 'default', toExtensions: ['html']});
});

it('overrides all default options with valid user options', () => {
const createRedirects: CreateRedirectsFnOption = (_routePath: string) => [];
expect(
normalizePluginOptions({
testValidate({
fromExtensions: ['exe', 'zip'],
toExtensions: ['html'],
createRedirects,
Expand All @@ -47,23 +53,23 @@ describe('normalizePluginOptions', () => {

it('rejects bad fromExtensions user inputs', () => {
expect(() =>
normalizePluginOptions({
testValidate({
fromExtensions: [null, undefined, 123, true] as unknown as string[],
}),
).toThrowErrorMatchingSnapshot();
});

it('rejects bad toExtensions user inputs', () => {
expect(() =>
normalizePluginOptions({
testValidate({
toExtensions: [null, undefined, 123, true] as unknown as string[],
}),
).toThrowErrorMatchingSnapshot();
});

it('rejects bad createRedirects user inputs', () => {
expect(() =>
normalizePluginOptions({
testValidate({
createRedirects: ['bad', 'value'] as unknown as CreateRedirectsFnOption,
}),
).toThrowErrorMatchingSnapshot();
Expand Down
7 changes: 3 additions & 4 deletions packages/docusaurus-plugin-client-redirects/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type {LoadContext, Plugin, Props} from '@docusaurus/types';
import type {PluginContext, RedirectMetadata} from './types';
import type {PluginOptions} from '@docusaurus/plugin-client-redirects';

import normalizePluginOptions from './normalizePluginOptions';
import collectRedirects from './collectRedirects';
import writeRedirectFiles, {
toRedirectFilesMetadata,
Expand All @@ -19,12 +18,10 @@ import {removePrefix, addLeadingSlash} from '@docusaurus/utils';

export default function pluginClientRedirectsPages(
context: LoadContext,
opts: PluginOptions,
options: PluginOptions,
): Plugin<unknown> {
const {trailingSlash} = context.siteConfig;

const options = normalizePluginOptions(opts);

return {
name: 'docusaurus-plugin-client-redirects',
async postBuild(props: Props) {
Expand Down Expand Up @@ -53,3 +50,5 @@ export default function pluginClientRedirectsPages(
},
};
}

export {validateOptions} from './options';

This file was deleted.

52 changes: 52 additions & 0 deletions packages/docusaurus-plugin-client-redirects/src/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* 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 type {
PluginOptions,
RedirectOption,
} from '@docusaurus/plugin-client-redirects';
import type {
OptionValidationContext,
ValidationResult,
} from '@docusaurus/types';
import {Joi, PathnameSchema} from '@docusaurus/utils-validation';

export const DEFAULT_OPTIONS: Partial<PluginOptions> = {
fromExtensions: [],
toExtensions: [],
redirects: [],
};

const RedirectPluginOptionValidation = Joi.object<RedirectOption>({
to: PathnameSchema.required(),
from: Joi.alternatives().try(
PathnameSchema.required(),
Joi.array().items(PathnameSchema.required()),
),
});

const isString = Joi.string().required().not(null);

const UserOptionsSchema = Joi.object<PluginOptions>({
fromExtensions: Joi.array()
.items(isString)
.default(DEFAULT_OPTIONS.fromExtensions),
toExtensions: Joi.array()
.items(isString)
.default(DEFAULT_OPTIONS.toExtensions),
redirects: Joi.array()
.items(RedirectPluginOptionValidation)
.default(DEFAULT_OPTIONS.redirects),
createRedirects: Joi.function().arity(1),
}).default(DEFAULT_OPTIONS);

export function validateOptions({
validate,
options: userOptions,
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
return validate(UserOptionsSchema, userOptions);
}

0 comments on commit da9f38b

Please sign in to comment.