/** * 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 logger from '@docusaurus/logger'; import Yaml from 'js-yaml'; import {PluginIdSchema} from './validationSchemas'; import type Joi from './Joi'; /** Print warnings returned from Joi validation. */ export function printWarning(warning?: Joi.ValidationError): void { if (warning) { const warningMessages = warning.details .map(({message}) => message) .join('\n'); logger.warn(warningMessages); } } /** * The callback that should be used to validate plugin options. Handles plugin * IDs on a generic level: no matter what the schema declares, this callback * would require a string ID or default to "default". */ export function normalizePluginOptions( schema: Joi.ObjectSchema, // This allows us to automatically normalize undefined to { id: "default" } options: Partial = {}, ): T { // All plugins can be provided an "id" option (multi-instance support) // we add schema validation automatically const finalSchema = schema.append({ id: PluginIdSchema, }); const {error, warning, value} = finalSchema.validate(options, { convert: false, }); printWarning(warning); if (error) { throw error; } return value; } /** * The callback that should be used to validate theme config. No matter what the * schema declares, this callback would allow unknown attributes. */ export function normalizeThemeConfig( schema: Joi.ObjectSchema, themeConfig: Partial, ): T { // A theme should only validate its "slice" of the full themeConfig, // not the whole object, so we allow unknown attributes // otherwise one theme would fail validating the data of another theme const finalSchema = schema.unknown(); const {error, warning, value} = finalSchema.validate(themeConfig, { convert: false, }); printWarning(warning); if (error) { throw error; } return value; } /** * Validate front matter with better error message */ export function validateFrontMatter( frontMatter: {[key: string]: unknown}, schema: Joi.ObjectSchema, ): T { const {value, error, warning} = schema.validate(frontMatter, { convert: true, allowUnknown: true, abortEarly: false, }); printWarning(warning); if (error) { const errorDetails = error.details; const invalidFields = errorDetails.map(({path}) => path).join(', '); logger.error`The following front matter: --- ${Yaml.dump(frontMatter)}--- contains invalid values for field(s): code=${invalidFields}. ${errorDetails.map(({message}) => message)} `; throw error; } return value; }