From fdb65de11555b75605e593db8e0fe7e177c69bdd Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Sat, 10 Oct 2020 22:37:35 -0700 Subject: [PATCH 1/9] misc: fix various validation issues in plugin-utils, uncopy typings and us extends to extend Joi types, feat: save validation results back into plugin options. --- .../__tests__/test-plugin-options-schema.ts | 2 +- packages/gatsby-plugin-utils/src/joi.ts | 7 +- .../utils/plugin-options-schema-joi-type.ts | 2257 ----------------- packages/gatsby-plugin-utils/src/validate.ts | 30 +- .../src/bootstrap/load-plugins/validate.ts | 15 +- 5 files changed, 31 insertions(+), 2280 deletions(-) delete mode 100644 packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts diff --git a/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts b/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts index ad07a281c2663..53ea74c384cac 100644 --- a/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts +++ b/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts @@ -1,5 +1,5 @@ import { testPluginOptionsSchema } from "../test-plugin-options-schema" -import { ObjectSchema } from "../utils/plugin-options-schema-joi-type" +import { ObjectSchema } from "joi" describe(`testPluginOptionsSchema`, () => { it(`should partially validate one value of a schema`, () => { diff --git a/packages/gatsby-plugin-utils/src/joi.ts b/packages/gatsby-plugin-utils/src/joi.ts index c2072a92bb61b..aebe391fcbb03 100644 --- a/packages/gatsby-plugin-utils/src/joi.ts +++ b/packages/gatsby-plugin-utils/src/joi.ts @@ -1,8 +1,9 @@ import joi from "joi" -import { PluginOptionsSchemaJoi } from "./utils/plugin-options-schema-joi-type" +import { Root } from "joi" -export * from "./utils/plugin-options-schema-joi-type" -export const Joi: PluginOptionsSchemaJoi = joi.extend({ +export type GatsbyPluginOptionsJoi = Root + +export const Joi: GatsbyPluginOptionsJoi = joi.extend({ // This tells Joi to extend _all_ types with .dotenv(), see // https://github.com/sideway/joi/commit/03adf22eb1f06c47d1583617093edee3a96b3873 // @ts-ignore Joi types weren't updated with that commit, PR: https://github.com/sideway/joi/pull/2477 diff --git a/packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts b/packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts deleted file mode 100644 index c56386f79d299..0000000000000 --- a/packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts +++ /dev/null @@ -1,2257 +0,0 @@ -/* eslint-disable */ -// The following definitions have been copied (almost) as-is from: -// https://github.com/sideway/joi/tree/master/lib/index.d.ts -// The only change @mxstbr made was to add support for our custom -// .dotenv extension to AnySchema. - -type Types = - | "any" - | "alternatives" - | "array" - | "boolean" - | "binary" - | "date" - | "function" - | "link" - | "number" - | "object" - | "string" - | "symbol" - -type BasicType = boolean | number | string | any[] | object | null - -type LanguageMessages = Record - -type PresenceMode = "optional" | "required" | "forbidden" - -interface ErrorFormattingOptions { - /** - * when true, error message templates will escape special characters to HTML entities, for security purposes. - * - * @default false - */ - escapeHtml?: boolean - /** - * defines the value used to set the label context variable. - */ - label?: "path" | "key" | false - /** - * The preferred language code for error messages. - * The value is matched against keys at the root of the messages object, and then the error code as a child key of that. - * Can be a reference to the value, global context, or local context which is the root value passed to the validation function. - * - * Note that references to the value are usually not what you want as they move around the value structure relative to where the error happens. - * Instead, either use the global context, or the absolute value (e.g. `Joi.ref('/variable')`) - */ - language?: keyof LanguageMessages - /** - * when false, skips rendering error templates. Useful when error messages are generated elsewhere to save processing time. - * - * @default true - */ - render?: boolean - /** - * when true, the main error will possess a stack trace, otherwise it will be disabled. - * Defaults to false for performances reasons. Has no effect on platforms other than V8/node.js as it uses the Stack trace API. - * - * @default false - */ - stack?: boolean - /** - * overrides the way values are wrapped (e.g. `[]` arround arrays, `""` around labels). - * Each key can be set to a string with one (same character before and after the value) or two characters (first character - * before and second character after), or `false` to disable wrapping. - */ - wrap?: { - /** - * the characters used around `{#label}` references. Defaults to `'"'`. - * - * @default '"' - */ - label?: string | false - - /** - * the characters used around array avlues. Defaults to `'[]'` - * - * @default '[]' - */ - array?: string | false - } -} - -interface BaseValidationOptions { - /** - * when true, stops validation on the first error, otherwise returns all the errors found. - * - * @default true - */ - abortEarly?: boolean - /** - * when true, allows object to contain unknown keys which are ignored. - * - * @default false - */ - allowUnknown?: boolean - /** - * when true, schema caching is enabled (for schemas with explicit caching rules). - * - * @default false - */ - cache?: boolean - /** - * provides an external data set to be used in references - */ - context?: Context - /** - * when true, attempts to cast values to the required types (e.g. a string to a number). - * - * @default true - */ - convert?: boolean - /** - * sets the string format used when converting dates to strings in error messages and casting. - * - * @default 'iso' - */ - dateFormat?: "date" | "iso" | "string" | "time" | "utc" - /** - * when true, valid results and throw errors are decorated with a debug property which includes an array of the validation steps used to generate the returned result. - * - * @default false - */ - debug?: boolean - /** - * error formatting settings. - */ - errors?: ErrorFormattingOptions - /** - * if false, the external rules set with `any.external()` are ignored, which is required to ignore any external validations in synchronous mode (or an exception is thrown). - * - * @default true - */ - externals?: boolean - /** - * when true, do not apply default values. - * - * @default false - */ - noDefaults?: boolean - /** - * when true, inputs are shallow cloned to include non-enumerables properties. - * - * @default false - */ - nonEnumerables?: boolean - /** - * sets the default presence requirements. Supported modes: 'optional', 'required', and 'forbidden'. - * - * @default 'optional' - */ - presence?: PresenceMode - /** - * when true, ignores unknown keys with a function value. - * - * @default false - */ - skipFunctions?: boolean - /** - * remove unknown elements from objects and arrays. - * - when true, all unknown elements will be removed - * - when an object: - * - objects - set to true to remove unknown keys from objects - * - * @default false - */ - stripUnknown?: boolean | { arrays?: boolean; objects?: boolean } -} - -interface ValidationOptions extends BaseValidationOptions { - /** - * overrides individual error messages. Defaults to no override (`{}`). - * Messages use the same rules as templates. - * Variables in double braces `{{var}}` are HTML escaped if the option `errors.escapeHtml` is set to true. - * - * @default {} - */ - messages?: LanguageMessages -} - -interface AsyncValidationOptions extends ValidationOptions { - /** - * when true, warnings are returned alongside the value (i.e. `{ value, warning }`). - * - * @default false - */ - warnings?: boolean -} - -interface LanguageMessageTemplate { - source: string - rendered: string -} - -interface ErrorValidationOptions extends BaseValidationOptions { - messages?: Record -} - -interface RenameOptions { - /** - * if true, does not delete the old key name, keeping both the new and old keys in place. - * - * @default false - */ - alias?: boolean - /** - * if true, allows renaming multiple keys to the same destination where the last rename wins. - * - * @default false - */ - multiple?: boolean - /** - * if true, allows renaming a key over an existing key. - * - * @default false - */ - override?: boolean - /** - * if true, skip renaming of a key if it's undefined. - * - * @default false - */ - ignoreUndefined?: boolean -} - -interface TopLevelDomainOptions { - /** - * - `true` to use the IANA list of registered TLDs. This is the default value. - * - `false` to allow any TLD not listed in the `deny` list, if present. - * - A `Set` or array of the allowed TLDs. Cannot be used together with `deny`. - */ - allow?: Set | string[] | boolean - /** - * - A `Set` or array of the forbidden TLDs. Cannot be used together with a custom `allow` list. - */ - deny?: Set | string[] -} - -interface HierarchySeparatorOptions { - /** - * overrides the default `.` hierarchy separator. Set to false to treat the key as a literal value. - * - * @default '.' - */ - separator?: string | false -} - -interface EmailOptions { - /** - * If `true`, Unicode characters are permitted - * - * @default true - */ - allowUnicode?: boolean - /** - * if `true`, ignore invalid email length errors. - * - * @default false - */ - ignoreLength?: boolean - /** - * if true, allows multiple email addresses in a single string, separated by , or the separator characters. - * - * @default false - */ - multiple?: boolean - /** - * when multiple is true, overrides the default , separator. String can be a single character or multiple separator characters. - * - * @default ',' - */ - separator?: string | string[] - /** - * Options for TLD (top level domain) validation. By default, the TLD must be a valid name listed on the [IANA registry](http://data.iana.org/TLD/tlds-alpha-by-domain.txt) - * - * @default { allow: true } - */ - tlds?: TopLevelDomainOptions | false - /** - * Number of segments required for the domain. Be careful since some domains, such as `io`, directly allow email. - * - * @default 2 - */ - minDomainSegments?: number -} - -interface DomainOptions { - /** - * If `true`, Unicode characters are permitted - * - * @default true - */ - allowUnicode?: boolean - - /** - * Options for TLD (top level domain) validation. By default, the TLD must be a valid name listed on the [IANA registry](http://data.iana.org/TLD/tlds-alpha-by-domain.txt) - * - * @default { allow: true } - */ - tlds?: TopLevelDomainOptions | false - /** - * Number of segments required for the domain. - * - * @default 2 - */ - minDomainSegments?: number -} - -interface HexOptions { - /** - * hex decoded representation must be byte aligned. - * @default false - */ - byteAligned?: boolean -} - -interface IpOptions { - /** - * One or more IP address versions to validate against. Valid values: ipv4, ipv6, ipvfuture - */ - version?: string | string[] - /** - * Used to determine if a CIDR is allowed or not. Valid values: optional, required, forbidden - */ - cidr?: PresenceMode -} - -type GuidVersions = "uuidv1" | "uuidv2" | "uuidv3" | "uuidv4" | "uuidv5" - -interface GuidOptions { - version: GuidVersions[] | GuidVersions -} - -interface UriOptions { - /** - * Specifies one or more acceptable Schemes, should only include the scheme name. - * Can be an Array or String (strings are automatically escaped for use in a Regular Expression). - */ - scheme?: string | RegExp | Array - /** - * Allow relative URIs. - * - * @default false - */ - allowRelative?: boolean - /** - * Restrict only relative URIs. - * - * @default false - */ - relativeOnly?: boolean - /** - * Allows unencoded square brackets inside the query string. - * This is NOT RFC 3986 compliant but query strings like abc[]=123&abc[]=456 are very common these days. - * - * @default false - */ - allowQuerySquareBrackets?: boolean - /** - * Validate the domain component using the options specified in `string.domain()`. - */ - domain?: DomainOptions -} - -interface DataUriOptions { - /** - * optional parameter defaulting to true which will require `=` padding if true or make padding optional if false - * - * @default true - */ - paddingRequired?: boolean -} - -interface Base64Options extends Pick { - /** - * if true, uses the URI-safe base64 format which replaces `+` with `-` and `\` with `_`. - * - * @default false - */ - urlSafe?: boolean -} - -interface SwitchCases { - /** - * the required condition joi type. - */ - is: SchemaLike - /** - * the alternative schema type if the condition is true. - */ - then: SchemaLike -} - -interface SwitchDefault { - /** - * the alternative schema type if no cases matched. - * Only one otherwise statement is allowed in switch as the last array item. - */ - otherwise: SchemaLike -} - -interface WhenOptions { - /** - * the required condition joi type. - */ - is?: SchemaLike - - /** - * the negative version of `is` (`then` and `otherwise` have reverse - * roles). - */ - not?: SchemaLike - - /** - * the alternative schema type if the condition is true. Required if otherwise or switch are missing. - */ - then?: SchemaLike - - /** - * the alternative schema type if the condition is false. Required if then or switch are missing. - */ - otherwise?: SchemaLike - - /** - * the list of cases. Required if then is missing. Required if then or otherwise are missing. - */ - switch?: Array - - /** - * whether to stop applying further conditions if the condition is true. - */ - break?: boolean -} - -interface WhenSchemaOptions { - /** - * the alternative schema type if the condition is true. Required if otherwise is missing. - */ - then?: SchemaLike - /** - * the alternative schema type if the condition is false. Required if then is missing. - */ - otherwise?: SchemaLike -} - -interface Cache { - /** - * Add an item to the cache. - * - * Note that key and value can be anything including objects, array, etc. - */ - set(key: any, value: any): void - - /** - * Retrieve an item from the cache. - * - * Note that key and value can be anything including objects, array, etc. - */ - get(key: any): any -} -interface CacheProvisionOptions { - /** - * number of items to store in the cache before the least used items are dropped. - * - * @default 1000 - */ - max: number -} - -interface CacheConfiguration { - /** - * Provisions a simple LRU cache for caching simple inputs (`undefined`, `null`, strings, numbers, and booleans). - */ - provision(options?: CacheProvisionOptions): void -} - -interface CompileOptions { - /** - * If true and the provided schema is (or contains parts) using an older version of joi, will return a compiled schema that is compatible with the older version. - * If false, the schema is always compiled using the current version and if older schema components are found, an error is thrown. - */ - legacy: boolean -} - -interface IsSchemaOptions { - /** - * If true, will identify schemas from older versions of joi, otherwise will throw an error. - * - * @default false - */ - legacy: boolean -} - -interface ReferenceOptions extends HierarchySeparatorOptions { - /** - * a function with the signature `function(value)` where `value` is the resolved reference value and the return value is the adjusted value to use. - * Note that the adjust feature will not perform any type validation on the adjusted value and it must match the value expected by the rule it is used in. - * Cannot be used with `map`. - * - * @example `(value) => value + 5` - */ - adjust?: (value: any) => any - - /** - * an array of array pairs using the format `[[key, value], [key, value]]` used to maps the resolved reference value to another value. - * If the resolved value is not in the map, it is returned as-is. - * Cannot be used with `adjust`. - */ - map?: Array<[any, any]> - - /** - * overrides default prefix characters. - */ - prefix?: { - /** - * references to the globally provided context preference. - * - * @default '$' - */ - global?: string - - /** - * references to error-specific or rule specific context. - * - * @default '#' - */ - local?: string - - /** - * references to the root value being validated. - * - * @default '/' - */ - root?: string - } - - /** - * If set to a number, sets the reference relative starting point. - * Cannot be combined with separator prefix characters. - * Defaults to the reference key prefix (or 1 if none present) - */ - ancestor?: number - - /** - * creates an in-reference. - */ - in?: boolean - - /** - * when true, the reference resolves by reaching into maps and sets. - */ - iterables?: boolean -} - -interface StringRegexOptions { - /** - * optional pattern name. - */ - name?: string - - /** - * when true, the provided pattern will be disallowed instead of required. - * - * @default false - */ - invert?: boolean -} - -interface RuleOptions { - /** - * if true, the rules will not be replaced by the same unique rule later. - * - * For example, `Joi.number().min(1).rule({ keep: true }).min(2)` will keep both `min()` rules instead of the later rule overriding the first. - * - * @default false - */ - keep?: boolean - - /** - * a single message string or a messages object where each key is an error code and corresponding message string as value. - * - * The object is the same as the messages used as an option in `any.validate()`. - * The strings can be plain messages or a message template. - */ - message?: string | LanguageMessages - - /** - * if true, turns any error generated by the ruleset to warnings. - */ - warn?: boolean -} - -interface ErrorReport extends Error { - code: string - flags: Record - path: string[] - prefs: ErrorValidationOptions - messages: LanguageMessages - state: State - value: any -} - -interface ValidationError extends Error { - name: "ValidationError" - - isJoi: boolean - - /** - * array of errors. - */ - details: ValidationErrorItem[] - - /** - * function that returns a string with an annotated version of the object pointing at the places where errors occurred. - * - * NOTE: This method does not exist in browser builds of Joi - * - * @param stripColors - if truthy, will strip the colors out of the output. - */ - annotate(stripColors?: boolean): string - - _object: any -} - -interface ValidationErrorItem { - message: string - path: Array - type: string - context?: Context -} - -type ValidationErrorFunction = ( - errors: ErrorReport[] -) => string | ValidationErrorItem | Error - -interface ValidationResult { - error?: ValidationError - errors?: ValidationError - warning?: ValidationError - value: any -} - -interface CreateErrorOptions { - flags?: boolean - messages?: LanguageMessages -} - -interface ModifyOptions { - each?: boolean - once?: boolean - ref?: boolean - schema?: boolean -} - -interface MutateRegisterOptions { - family?: any - key?: any -} - -interface SetFlagOptions { - clone: boolean -} - -interface CustomHelpers { - schema: ExtensionBoundSchema - state: State - prefs: ValidationOptions - original: V - warn: (code: string, local?: Context) => void - error: (code: string, local?: Context) => ErrorReport - message: (messages: LanguageMessages, local?: Context) => ErrorReport -} - -type CustomValidator = (value: V, helpers: CustomHelpers) => V - -type ExternalValidationFunction = (value: any) => any - -type SchemaLikeWithoutArray = - | string - | number - | boolean - | null - | Schema - | SchemaMap -type SchemaLike = SchemaLikeWithoutArray | object - -type SchemaMap = { - [key in keyof TSchema]?: SchemaLike | SchemaLike[] -} - -export type Schema = - | AnySchema - | ArraySchema - | AlternativesSchema - | BinarySchema - | BooleanSchema - | DateSchema - | FunctionSchema - | NumberSchema - | ObjectSchema - | StringSchema - | LinkSchema - | SymbolSchema - -type SchemaFunction = (schema: Schema) => Schema - -interface AddRuleOptions { - name: string - args?: { - [key: string]: any - } -} - -interface GetRuleOptions { - args?: Record - method?: string - name: string - operator?: string -} - -interface SchemaInternals { - /** - * Parent schema object. - */ - $_super: Schema - - /** - * Terms of current schema. - */ - $_terms: Record - - /** - * Adds a rule to current validation schema. - */ - $_addRule(rule: string | AddRuleOptions): Schema - - /** - * Internally compiles schema. - */ - $_compile(schema: SchemaLike, options?: CompileOptions): Schema - - /** - * Creates a joi error object. - */ - $_createError( - code: string, - value: any, - context: Context, - state: State, - prefs: ValidationOptions, - options?: CreateErrorOptions - ): Err - - /** - * Get value from given flag. - */ - $_getFlag(name: string): any - - /** - * Retrieve some rule configuration. - */ - $_getRule(name: string): GetRuleOptions | undefined - - $_mapLabels(path: string | string[]): string - - /** - * Returns true if validations runs fine on given value. - */ - $_match(value: any, state: State, prefs: ValidationOptions): boolean - - $_modify(options?: ModifyOptions): Schema - - /** - * Resets current schema. - */ - $_mutateRebuild(): this - - $_mutateRegister(schema: Schema, options?: MutateRegisterOptions): void - - /** - * Get value from given property. - */ - $_property(name: string): any - - /** - * Get schema at given path. - */ - $_reach(path: string[]): Schema - - /** - * Get current schema root references. - */ - $_rootReferences(): any - - /** - * Set flag to given value. - */ - $_setFlag(flag: string, value: any, options?: SetFlagOptions): void - - /** - * Runs internal validations against given value. - */ - $_validate( - value: any, - state: State, - prefs: ValidationOptions - ): ValidationResult -} - -interface AnySchema extends SchemaInternals { - /** - * Flags of current schema. - */ - _flags: Record - - /** - * Starts a ruleset in order to apply multiple rule options. The set ends when `rule()`, `keep()`, `message()`, or `warn()` is called. - */ - $: this - - /** - * Starts a ruleset in order to apply multiple rule options. The set ends when `rule()`, `keep()`, `message()`, or `warn()` is called. - */ - ruleset: this - - type?: Types | string - - /** - * Whitelists a value - */ - allow(...values: any[]): this - - /** - * Assign target alteration options to a schema that are applied when `any.tailor()` is called. - * @param targets - an object where each key is a target name, and each value is a function that takes an schema and returns an schema. - */ - alter(targets: Record): this - - /** - * By default, some Joi methods to function properly need to rely on the Joi instance they are attached to because - * they use `this` internally. - * So `Joi.string()` works but if you extract the function from it and call `string()` it won't. - * `bind()` creates a new Joi instance where all the functions relying on `this` are bound to the Joi instance. - */ - bind(): this - - /** - * Adds caching to the schema which will attempt to cache the validation results (success and failures) of incoming inputs. - * If no cache is passed, a default cache is provisioned by using `cache.provision()` internally. - */ - cache(cache?: Cache): this - - /** - * Casts the validated value to the specified type. - */ - cast(to: "map" | "number" | "set" | "string"): this - - /** - * Returns a new type that is the result of adding the rules of one type to another. - */ - concat(schema: this): this - - /** - * Adds a custom validation function. - */ - custom(fn: CustomValidator, description?: string): this - - /** - * Sets a default value if the original value is `undefined` where: - * @param value - the default value. One of: - * - a literal value (string, number, object, etc.) - * - a [references](#refkey-options) - * - a function which returns the default value using the signature `function(parent, helpers)` where: - * - `parent` - a clone of the object containing the value being validated. Note that since specifying a - * `parent` ragument performs cloning, do not declare format arguments if you are not using them. - * - `helpers` - same as thsoe described in [`any.custom()`](anycustomermethod_description) - * - * When called without any `value` on an object schema type, a default value will be automatically generated - * based on the default values of the object keys. - * - * Note that if value is an object, any changes to the object after `default()` is called will change the - * reference and any future assignment. - */ - default( - value?: - | BasicType - | Reference - | ((parent: any, helpers: CustomHelpers) => BasicType | Reference) - ): this - - /** - * Returns a plain object representing the schema's rules and properties - */ - describe(): Description - - /** - * Annotates the key - */ - description(desc: string): this - - /** - * Disallows values. - */ - disallow(...values: any[]): this - - /** - * Specifies that a value should be stored in a .env file with ${name} - * instead of inlined into the gatsby-config.js - * @param name - string - */ - dotenv(name: string): this - - /** - * Considers anything that matches the schema to be empty (undefined). - * @param schema - any object or joi schema to match. An undefined schema unsets that rule. - */ - empty(schema?: SchemaLike): this - - /** - * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed. - */ - equal(...values: any[]): this - - /** - * Overrides the default joi error with a custom error if the rule fails where: - * @param err - can be: - * an instance of `Error` - the override error. - * a `function(errors)`, taking an array of errors as argument, where it must either: - * return a `string` - substitutes the error message with this text - * return a single ` object` or an `Array` of it, where: - * `type` - optional parameter providing the type of the error (eg. `number.min`). - * `message` - optional parameter if `template` is provided, containing the text of the error. - * `template` - optional parameter if `message` is provided, containing a template string, using the same format as usual joi language errors. - * `context` - optional parameter, to provide context to your error if you are using the `template`. - * return an `Error` - same as when you directly provide an `Error`, but you can customize the error message based on the errors. - * - * Note that if you provide an `Error`, it will be returned as-is, unmodified and undecorated with any of the - * normal joi error properties. If validation fails and another error is found before the error - * override, that error will be returned and the override will be ignored (unless the `abortEarly` - * option has been set to `false`). - */ - error(err: Error | ValidationErrorFunction): this - - /** - * Annotates the key with an example value, must be valid. - */ - example(value: any, options?: { override: boolean }): this - - /** - * Marks a key as required which will not allow undefined as value. All keys are optional by default. - */ - exist(): this - - /** - * Adds an external validation rule. - * - * Note that external validation rules are only called after the all other validation rules for the entire schema (from the value root) are checked. - * This means that any changes made to the value by the external rules are not available to any other validation rules during the non-external validation phase. - * If schema validation failed, no external validation rules are called. - */ - external(method: ExternalValidationFunction, description?: string): this - - /** - * Returns a sub-schema based on a path of object keys or schema ids. - * - * @param path - a dot `.` separated path string or a pre-split array of path keys. The keys must match the sub-schema id or object key (if no id was explicitly set). - */ - extract(path: string | string[]): Schema - - /** - * Sets a failover value if the original value fails passing validation. - * - * @param value - the failover value. value supports references. value may be assigned a function which returns the default value. - * - * If value is specified as a function that accepts a single parameter, that parameter will be a context object that can be used to derive the resulting value. - * Note that if value is an object, any changes to the object after `failover()` is called will change the reference and any future assignment. - * Use a function when setting a dynamic value (e.g. the current time). - * Using a function with a single argument performs some internal cloning which has a performance impact. - * If you do not need access to the context, define the function without any arguments. - */ - failover(value: any): this - - /** - * Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys. - */ - forbidden(): this - - /** - * Returns a new schema where each of the path keys listed have been modified. - * - * @param key - an array of key strings, a single key string, or an array of arrays of pre-split key strings. - * @param adjuster - a function which must return a modified schema. - */ - fork(key: string | string[] | string[][], adjuster: SchemaFunction): this - - /** - * Sets a schema id for reaching into the schema via `any.extract()`. - * If no id is set, the schema id defaults to the object key it is associated with. - * If the schema is used in an array or alternatives type and no id is set, the schema in unreachable. - */ - id(name?: string): this - - /** - * Disallows values. - */ - invalid(...values: any[]): this - - /** - * Same as `rule({ keep: true })`. - * - * Note that `keep()` will terminate the current ruleset and cannot be followed by another rule option. - * Use `rule()` to apply multiple rule options. - */ - keep(): this - - /** - * Overrides the key name in error messages. - */ - label(name: string): this - - /** - * Same as `rule({ message })`. - * - * Note that `message()` will terminate the current ruleset and cannot be followed by another rule option. - * Use `rule()` to apply multiple rule options. - */ - message(message: string): this - - /** - * Same as `any.prefs({ messages })`. - * Note that while `any.message()` applies only to the last rule or ruleset, `any.messages()` applies to the entire schema. - */ - messages(messages: LanguageMessages): this - - /** - * Attaches metadata to the key. - */ - meta(meta: object): this - - /** - * Disallows values. - */ - not(...values: any[]): this - - /** - * Annotates the key - */ - note(...notes: string[]): this - - /** - * Requires the validated value to match of the provided `any.allow()` values. - * It has not effect when called together with `any.valid()` since it already sets the requirements. - * When used with `any.allow()` it converts it to an `any.valid()`. - */ - only(): this - - /** - * Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default. - */ - optional(): this - - /** - * Overrides the global validate() options for the current key and any sub-key. - */ - options(options: ValidationOptions): this - - /** - * Overrides the global validate() options for the current key and any sub-key. - */ - prefs(options: ValidationOptions): this - - /** - * Overrides the global validate() options for the current key and any sub-key. - */ - preferences(options: ValidationOptions): this - - /** - * Sets the presence mode for the schema. - */ - presence(mode: PresenceMode): this - - /** - * Outputs the original untouched value instead of the casted value. - */ - raw(enabled?: boolean): this - - /** - * Marks a key as required which will not allow undefined as value. All keys are optional by default. - */ - required(): this - - /** - * Applies a set of rule options to the current ruleset or last rule added. - * - * When applying rule options, the last rule (e.g. `min()`) is used unless there is an active ruleset defined (e.g. `$.min().max()`) - * in which case the options are applied to all the provided rules. - * Once `rule()` is called, the previous rules can no longer be modified and any active ruleset is terminated. - * - * Rule modifications can only be applied to supported rules. - * Most of the `any` methods do not support rule modifications because they are implemented using schema flags (e.g. `required()`) or special - * internal implementation (e.g. `valid()`). - * In those cases, use the `any.messages()` method to override the error codes for the errors you want to customize. - */ - rule(options: RuleOptions): this - - /** - * Registers a schema to be used by decendents of the current schema in named link references. - */ - shared(ref: Schema): this - - /** - * Sets the options.convert options to false which prevent type casting for the current key and any child keys. - */ - strict(isStrict?: boolean): this - - /** - * Marks a key to be removed from a resulting object or array after validation. Used to sanitize output. - * @param [enabled=true] - if true, the value is stripped, otherwise the validated value is retained. Defaults to true. - */ - strip(enabled?: boolean): this - - /** - * Annotates the key - */ - tag(...tags: string[]): this - - /** - * Applies any assigned target alterations to a copy of the schema that were applied via `any.alter()`. - */ - tailor(targets: string | string[]): Schema - - /** - * Annotates the key with an unit name. - */ - unit(name: string): this - - /** - * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed. - */ - valid(...values: any[]): this - - /** - * Validates a value using the schema and options. - */ - validate(value: any, options?: ValidationOptions): ValidationResult - - /** - * Validates a value using the schema and options. - */ - validateAsync(value: any, options?: AsyncValidationOptions): Promise - - /** - * Same as `rule({ warn: true })`. - * Note that `warn()` will terminate the current ruleset and cannot be followed by another rule option. - * Use `rule()` to apply multiple rule options. - */ - warn(): this - - /** - * Generates a warning. - * When calling `any.validateAsync()`, set the `warning` option to true to enable warnings. - * Warnings are reported separately from errors alongside the result value via the warning key (i.e. `{ value, warning }`). - * Warning are always included when calling `any.validate()`. - */ - warning(code: string, context: Context): this - - /** - * Converts the type into an alternatives type where the conditions are merged into the type definition where: - */ - when(ref: string | Reference, options: WhenOptions): this - - /** - * Converts the type into an alternatives type where the conditions are merged into the type definition where: - */ - when(ref: Schema, options: WhenSchemaOptions): this -} - -interface Description { - type?: Types | string - label?: string - description?: string - flags?: object - notes?: string[] - tags?: string[] - meta?: any[] - example?: any[] - valids?: any[] - invalids?: any[] - unit?: string - options?: ValidationOptions - [key: string]: any -} - -interface Context { - [key: string]: any - key?: string - label?: string - value?: any -} - -interface State { - key?: string - path?: string - parent?: any - reference?: any - ancestors?: any - localize?(...args: any[]): State -} - -interface BooleanSchema extends AnySchema { - /** - * Allows for additional values to be considered valid booleans by converting them to false during validation. - * String comparisons are by default case insensitive, - * see `boolean.sensitive()` to change this behavior. - * @param values - strings, numbers or arrays of them - */ - falsy(...values: Array): this - - /** - * Allows the values provided to truthy and falsy as well as the "true" and "false" default conversion - * (when not in `strict()` mode) to be matched in a case insensitive manner. - */ - sensitive(enabled?: boolean): this - - /** - * Allows for additional values to be considered valid booleans by converting them to true during validation. - * String comparisons are by default case insensitive, see `boolean.sensitive()` to change this behavior. - * @param values - strings, numbers or arrays of them - */ - truthy(...values: Array): this -} - -interface NumberSchema extends AnySchema { - /** - * Specifies that the value must be greater than limit. - * It can also be a reference to another field. - */ - greater(limit: number | Reference): this - - /** - * Requires the number to be an integer (no floating point). - */ - integer(): this - - /** - * Specifies that the value must be less than limit. - * It can also be a reference to another field. - */ - less(limit: number | Reference): this - - /** - * Specifies the maximum value. - * It can also be a reference to another field. - */ - max(limit: number | Reference): this - - /** - * Specifies the minimum value. - * It can also be a reference to another field. - */ - min(limit: number | Reference): this - - /** - * Specifies that the value must be a multiple of base. - */ - multiple(base: number | Reference): this - - /** - * Requires the number to be negative. - */ - negative(): this - - /** - * Requires the number to be a TCP port, so between 0 and 65535. - */ - port(): this - - /** - * Requires the number to be positive. - */ - positive(): this - - /** - * Specifies the maximum number of decimal places where: - * @param limit - the maximum number of decimal places allowed. - */ - precision(limit: number): this - - /** - * Requires the number to be negative or positive. - */ - sign(sign: "positive" | "negative"): this - - /** - * Allows the number to be outside of JavaScript's safety range (Number.MIN_SAFE_INTEGER & Number.MAX_SAFE_INTEGER). - */ - unsafe(enabled?: any): this -} - -interface StringSchema extends AnySchema { - /** - * Requires the string value to only contain a-z, A-Z, and 0-9. - */ - alphanum(): this - - /** - * Requires the string value to be a valid base64 string; does not check the decoded value. - */ - base64(options?: Base64Options): this - - /** - * Sets the required string case. - */ - case(direction: "upper" | "lower"): this - - /** - * Requires the number to be a credit card number (Using Lunh Algorithm). - */ - creditCard(): this - - /** - * Requires the string value to be a valid data URI string. - */ - dataUri(options?: DataUriOptions): this - - /** - * Requires the string value to be a valid domain. - */ - domain(options?: DomainOptions): this - - /** - * Requires the string value to be a valid email address. - */ - email(options?: EmailOptions): this - - /** - * Requires the string value to be a valid GUID. - */ - guid(options?: GuidOptions): this - - /** - * Requires the string value to be a valid hexadecimal string. - */ - hex(options?: HexOptions): this - - /** - * Requires the string value to be a valid hostname as per RFC1123. - */ - hostname(): this - - /** - * Allows the value to match any whitelist of blacklist item in a case insensitive comparison. - */ - insensitive(): this - - /** - * Requires the string value to be a valid ip address. - */ - ip(options?: IpOptions): this - - /** - * Requires the string value to be in valid ISO 8601 date format. - */ - isoDate(): this - - /** - * Requires the string value to be in valid ISO 8601 duration format. - */ - isoDuration(): this - - /** - * Specifies the exact string length required - * @param limit - the required string length. It can also be a reference to another field. - * @param encoding - if specified, the string length is calculated in bytes using the provided encoding. - */ - length(limit: number | Reference, encoding?: string): this - - /** - * Requires the string value to be all lowercase. If the validation convert option is on (enabled by default), the string will be forced to lowercase. - */ - lowercase(): this - - /** - * Specifies the maximum number of string characters. - * @param limit - the maximum number of string characters allowed. It can also be a reference to another field. - * @param encoding - if specified, the string length is calculated in bytes using the provided encoding. - */ - max(limit: number | Reference, encoding?: string): this - - /** - * Specifies the minimum number string characters. - * @param limit - the minimum number of string characters required. It can also be a reference to another field. - * @param encoding - if specified, the string length is calculated in bytes using the provided encoding. - */ - min(limit: number | Reference, encoding?: string): this - - /** - * Requires the string value to be in a unicode normalized form. If the validation convert option is on (enabled by default), the string will be normalized. - * @param [form='NFC'] - The unicode normalization form to use. Valid values: NFC [default], NFD, NFKC, NFKD - */ - normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD"): this - - /** - * Defines a regular expression rule. - * @param pattern - a regular expression object the string value must match against. - * @param options - optional, can be: - * Name for patterns (useful with multiple patterns). Defaults to 'required'. - * An optional configuration object with the following supported properties: - * name - optional pattern name. - * invert - optional boolean flag. Defaults to false behavior. If specified as true, the provided pattern will be disallowed instead of required. - */ - pattern(pattern: RegExp, options?: string | StringRegexOptions): this - - /** - * Defines a regular expression rule. - * @param pattern - a regular expression object the string value must match against. - * @param options - optional, can be: - * Name for patterns (useful with multiple patterns). Defaults to 'required'. - * An optional configuration object with the following supported properties: - * name - optional pattern name. - * invert - optional boolean flag. Defaults to false behavior. If specified as true, the provided pattern will be disallowed instead of required. - */ - regex(pattern: RegExp, options?: string | StringRegexOptions): this - - /** - * Replace characters matching the given pattern with the specified replacement string where: - * @param pattern - a regular expression object to match against, or a string of which all occurrences will be replaced. - * @param replacement - the string that will replace the pattern. - */ - replace(pattern: RegExp | string, replacement: string): this - - /** - * Requires the string value to only contain a-z, A-Z, 0-9, and underscore _. - */ - token(): this - - /** - * Requires the string value to contain no whitespace before or after. If the validation convert option is on (enabled by default), the string will be trimmed. - * @param [enabled=true] - optional parameter defaulting to true which allows you to reset the behavior of trim by providing a falsy value. - */ - trim(enabled?: any): this - - /** - * Specifies whether the string.max() limit should be used as a truncation. - * @param [enabled=true] - optional parameter defaulting to true which allows you to reset the behavior of truncate by providing a falsy value. - */ - truncate(enabled?: boolean): this - - /** - * Requires the string value to be all uppercase. If the validation convert option is on (enabled by default), the string will be forced to uppercase. - */ - uppercase(): this - - /** - * Requires the string value to be a valid RFC 3986 URI. - */ - uri(options?: UriOptions): this - - /** - * Requires the string value to be a valid GUID. - */ - uuid(options?: GuidOptions): this -} - -interface SymbolSchema extends AnySchema { - // TODO: support number and symbol index - map( - iterable: - | Iterable<[string | number | boolean | symbol, symbol]> - | { [key: string]: symbol } - ): this -} - -interface ArraySortOptions { - /** - * @default 'ascending' - */ - order?: "ascending" | "descending" - by?: string | Reference -} - -interface ArrayUniqueOptions extends HierarchySeparatorOptions { - /** - * if true, undefined values for the dot notation string comparator will not cause the array to fail on uniqueness. - * - * @default false - */ - ignoreUndefined?: boolean -} - -type ComparatorFunction = (a: any, b: any) => boolean - -interface ArraySchema extends AnySchema { - /** - * Verifies that an assertion passes for at least one item in the array, where: - * `schema` - the validation rules required to satisfy the assertion. If the `schema` includes references, they are resolved against - * the array item being tested, not the value of the `ref` target. - */ - has(schema: SchemaLike): this - - /** - * List the types allowed for the array values. - * If a given type is .required() then there must be a matching item in the array. - * If a type is .forbidden() then it cannot appear in the array. - * Required items can be added multiple times to signify that multiple items must be found. - * Errors will contain the number of items that didn't match. - * Any unmatched item having a label will be mentioned explicitly. - * - * @param type - a joi schema object to validate each array item against. - */ - items(...types: SchemaLikeWithoutArray[]): this - - /** - * Specifies the exact number of items in the array. - */ - length(limit: number | Reference): this - - /** - * Specifies the maximum number of items in the array. - */ - max(limit: number | Reference): this - - /** - * Specifies the minimum number of items in the array. - */ - min(limit: number | Reference): this - - /** - * Lists the types in sequence order for the array values where: - * @param type - a joi schema object to validate against each array item in sequence order. type can be multiple values passed as individual arguments. - * If a given type is .required() then there must be a matching item with the same index position in the array. - * Errors will contain the number of items that didn't match. - * Any unmatched item having a label will be mentioned explicitly. - */ - ordered(...types: SchemaLikeWithoutArray[]): this - - /** - * Allow single values to be checked against rules as if it were provided as an array. - * enabled can be used with a falsy value to go back to the default behavior. - */ - single(enabled?: any): this - - /** - * Sorts the array by given order. - */ - sort(options?: ArraySortOptions): this - - /** - * Allow this array to be sparse. - * enabled can be used with a falsy value to go back to the default behavior. - */ - sparse(enabled?: any): this - - /** - * Requires the array values to be unique. - * Remember that if you provide a custom comparator function, - * different types can be passed as parameter depending on the rules you set on items. - * Be aware that a deep equality is performed on elements of the array having a type of object, - * a performance penalty is to be expected for this kind of operation. - */ - unique( - comparator?: string | ComparatorFunction, - options?: ArrayUniqueOptions - ): this -} - -interface ObjectPatternOptions { - fallthrough?: boolean - matches: SchemaLike | Reference -} - -export interface ObjectSchema extends AnySchema { - /** - * Defines an all-or-nothing relationship between keys where if one of the peers is present, all of them are required as well. - * - * Optional settings must be the last argument. - */ - and(...peers: Array): this - - /** - * Appends the allowed object keys. If schema is null, undefined, or {}, no changes will be applied. - */ - append(schema?: SchemaMap): this - - /** - * Verifies an assertion where. - */ - assert(ref: string | Reference, schema: SchemaLike, message?: string): this - - /** - * Requires the object to be an instance of a given constructor. - * - * @param constructor - the constructor function that the object must be an instance of. - * @param name - an alternate name to use in validation errors. This is useful when the constructor function does not have a name. - */ - // tslint:disable-next-line:ban-types - instance(constructor: Function, name?: string): this - - /** - * Sets or extends the allowed object keys. - */ - keys(schema?: SchemaMap): this - - /** - * Specifies the exact number of keys in the object. - */ - length(limit: number): this - - /** - * Specifies the maximum number of keys in the object. - */ - max(limit: number | Reference): this - - /** - * Specifies the minimum number of keys in the object. - */ - min(limit: number | Reference): this - - /** - * Defines a relationship between keys where not all peers can be present at the same time. - * - * Optional settings must be the last argument. - */ - nand(...peers: Array): this - - /** - * Defines a relationship between keys where one of the peers is required (and more than one is allowed). - * - * Optional settings must be the last argument. - */ - or(...peers: Array): this - - /** - * Defines an exclusive relationship between a set of keys where only one is allowed but none are required. - * - * Optional settings must be the last argument. - */ - oxor(...peers: Array): this - - /** - * Specify validation rules for unknown keys matching a pattern. - * - * @param pattern - a pattern that can be either a regular expression or a joi schema that will be tested against the unknown key names - * @param schema - the schema object matching keys must validate against - */ - pattern( - pattern: RegExp | SchemaLike, - schema: SchemaLike, - options?: ObjectPatternOptions - ): this - - /** - * Requires the object to be a Joi reference. - */ - ref(): this - - /** - * Requires the object to be a `RegExp` object. - */ - regex(): this - - /** - * Renames a key to another name (deletes the renamed key). - */ - rename(from: string | RegExp, to: string, options?: RenameOptions): this - - /** - * Requires the object to be a Joi schema instance. - */ - schema(type?: SchemaLike): this - - /** - * Overrides the handling of unknown keys for the scope of the current object only (does not apply to children). - */ - unknown(allow?: boolean): this - - /** - * Requires the presence of other keys whenever the specified key is present. - */ - with( - key: string, - peers: string | string[], - options?: HierarchySeparatorOptions - ): this - - /** - * Forbids the presence of other keys whenever the specified is present. - */ - without( - key: string, - peers: string | string[], - options?: HierarchySeparatorOptions - ): this - - /** - * Defines an exclusive relationship between a set of keys. one of them is required but not at the same time. - * - * Optional settings must be the last argument. - */ - xor(...peers: Array): this -} - -interface BinarySchema extends AnySchema { - /** - * Sets the string encoding format if a string input is converted to a buffer. - */ - encoding(encoding: string): this - - /** - * Specifies the minimum length of the buffer. - */ - min(limit: number | Reference): this - - /** - * Specifies the maximum length of the buffer. - */ - max(limit: number | Reference): this - - /** - * Specifies the exact length of the buffer: - */ - length(limit: number | Reference): this -} - -interface DateSchema extends AnySchema { - /** - * Specifies that the value must be greater than date. - * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, - * allowing to explicitly ensure a date is either in the past or in the future. - * It can also be a reference to another field. - */ - greater(date: "now" | Date | number | string | Reference): this - - /** - * Requires the string value to be in valid ISO 8601 date format. - */ - iso(): this - - /** - * Specifies that the value must be less than date. - * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, - * allowing to explicitly ensure a date is either in the past or in the future. - * It can also be a reference to another field. - */ - less(date: "now" | Date | number | string | Reference): this - - /** - * Specifies the oldest date allowed. - * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, - * allowing to explicitly ensure a date is either in the past or in the future. - * It can also be a reference to another field. - */ - min(date: "now" | Date | number | string | Reference): this - - /** - * Specifies the latest date allowed. - * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, - * allowing to explicitly ensure a date is either in the past or in the future. - * It can also be a reference to another field. - */ - max(date: "now" | Date | number | string | Reference): this - - /** - * Requires the value to be a timestamp interval from Unix Time. - * @param type - the type of timestamp (allowed values are unix or javascript [default]) - */ - timestamp(type?: "javascript" | "unix"): this -} - -interface FunctionSchema extends ObjectSchema { - /** - * Specifies the arity of the function where: - * @param n - the arity expected. - */ - arity(n: number): this - - /** - * Requires the function to be a class. - */ - class(): this - - /** - * Specifies the minimal arity of the function where: - * @param n - the minimal arity expected. - */ - minArity(n: number): this - - /** - * Specifies the minimal arity of the function where: - * @param n - the minimal arity expected. - */ - maxArity(n: number): this -} - -interface AlternativesSchema extends AnySchema { - /** - * Adds a conditional alternative schema type, either based on another key value, or a schema peeking into the current value. - */ - conditional(ref: string | Reference, options: WhenOptions): this - conditional(ref: Schema, options: WhenSchemaOptions): this - - /** - * Requires the validated value to match a specific set of the provided alternative.try() schemas. - * Cannot be combined with `alternatives.conditional()`. - */ - match(mode: "any" | "all" | "one"): this - - /** - * Adds an alternative schema type for attempting to match against the validated value. - */ - try(...types: SchemaLikeWithoutArray[]): this -} - -interface LinkSchema extends AnySchema { - /** - * Same as `any.concat()` but the schema is merged after the link is resolved which allows merging with schemas of the same type as the resolved link. - * Will throw an exception during validation if the merged types are not compatible. - */ - concat(schema: Schema): this - - /** - * Initializes the schema after constructions for cases where the schema has to be constructed first and then initialized. - * If `ref` was not passed to the constructor, `link.ref()` must be called prior to usaged. - */ - ref(ref: string): this -} - -interface Reference extends Exclude { - depth: number - type: string - key: string - root: string - path: string[] - display: string - toString(): string -} - -type ExtensionBoundSchema = Schema & SchemaInternals - -interface RuleArgs { - name: string - ref?: boolean - assert?: ((value: any) => boolean) | AnySchema - message?: string - - /** - * Undocumented properties - */ - normalize?(value: any): any -} - -type RuleMethod = (...args: any[]) => any - -interface ExtensionRule { - /** - * alternative name for this rule. - */ - alias?: string - /** - * whether rule supports multiple invocations. - */ - multi?: boolean - /** - * Dual rule: converts or validates. - */ - convert?: boolean - /** - * list of arguments accepted by `method`. - */ - args?: Array - /** - * rule body. - */ - method?: RuleMethod | false - /** - * validation function. - */ - validate?( - value: any, - helpers: any, - args: Record, - options: any - ): any - - /** - * undocumented flags. - */ - priority?: boolean - manifest?: boolean -} - -interface CoerceResult { - errors?: ErrorReport[] - value?: any -} - -type CoerceFunction = (value: any, helpers: CustomHelpers) => CoerceResult - -interface CoerceObject { - method: CoerceFunction - from?: string | string[] -} - -interface ExtensionFlag { - setter?: string - default?: any -} - -interface ExtensionTermManifest { - mapped: { - from: string - to: string - } -} - -interface ExtensionTerm { - init: any[] | null - register?: any - manifest?: Record -} - -interface Extension { - type: string - args?(...args: SchemaLike[]): Schema - base?: Schema - coerce?: CoerceFunction | CoerceObject - flags?: Record - manifest?: { - build?(obj: ExtensionBoundSchema, desc: Record): any - } - messages?: LanguageMessages | string - modifiers?: Record any> - overrides?: Record Schema> - prepare?(value: any, helpers: CustomHelpers): any - rebuild?(schema: ExtensionBoundSchema): void - rules?: Record> - terms?: Record - validate?(value: any, helpers: CustomHelpers): any - - /** - * undocumented options - */ - cast?: Record< - string, - { from(value: any): any; to(value: any, helpers: CustomHelpers): any } - > - properties?: Record -} - -type ExtensionFactory = (joi: PluginOptionsSchemaJoi) => Extension - -interface Err { - toString(): string -} - -// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- - -export interface PluginOptionsSchemaJoi { - /** - * Current version of the joi package. - */ - version: string - - ValidationError: new ( - message: string, - details: any, - original: any - ) => ValidationError - - /** - * Generates a schema object that matches any data type. - */ - any(): AnySchema - - /** - * Generates a schema object that matches an array data type. - */ - array(): ArraySchema - - /** - * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool(). - */ - bool(): BooleanSchema - - /** - * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool(). - */ - boolean(): BooleanSchema - - /** - * Generates a schema object that matches a Buffer data type (as well as the strings which will be converted to Buffers). - */ - binary(): BinarySchema - - /** - * Generates a schema object that matches a date type (as well as a JavaScript date string or number of milliseconds). - */ - date(): DateSchema - - /** - * Generates a schema object that matches a function type. - */ - func(): FunctionSchema - - /** - * Generates a schema object that matches a function type. - */ - function(): FunctionSchema - - /** - * Generates a schema object that matches a number data type (as well as strings that can be converted to numbers). - */ - number(): NumberSchema - - /** - * Generates a schema object that matches an object data type (as well as JSON strings that have been parsed into objects). - */ - // tslint:disable-next-line:no-unnecessary-generics - object( - schema?: SchemaMap - ): ObjectSchema - - /** - * Generates a schema object that matches a string data type. Note that empty strings are not allowed by default and must be enabled with allow(''). - */ - string(): StringSchema - - /** - * Generates a schema object that matches any symbol. - */ - symbol(): SymbolSchema - - /** - * Generates a type that will match one of the provided alternative schemas - */ - alternatives(types: SchemaLike[]): AlternativesSchema - alternatives(...types: SchemaLike[]): AlternativesSchema - - /** - * Alias for `alternatives` - */ - alt(types: SchemaLike[]): AlternativesSchema - alt(...types: SchemaLike[]): AlternativesSchema - - /** - * Links to another schema node and reuses it for validation, typically for creative recursive schemas. - * - * @param ref - the reference to the linked schema node. - * Cannot reference itself or its children as well as other links. - * Links can be expressed in relative terms like value references (`Joi.link('...')`), - * in absolute terms from the schema run-time root (`Joi.link('/a')`), - * or using schema ids implicitly using object keys or explicitly using `any.id()` (`Joi.link('#a.b.c')`). - */ - link(ref?: string): LinkSchema - - /** - * Validates a value against a schema and throws if validation fails. - * - * @param value - the value to validate. - * @param schema - the schema object. - * @param message - optional message string prefix added in front of the error message. may also be an Error object. - */ - assert(value: any, schema: Schema, options?: ValidationOptions): void - assert( - value: any, - schema: Schema, - message: string | Error, - options?: ValidationOptions - ): void - - /** - * Validates a value against a schema, returns valid object, and throws if validation fails. - * - * @param value - the value to validate. - * @param schema - the schema object. - * @param message - optional message string prefix added in front of the error message. may also be an Error object. - */ - attempt(value: any, schema: Schema, options?: ValidationOptions): any - attempt( - value: any, - schema: Schema, - message: string | Error, - options?: ValidationOptions - ): any - - cache: CacheConfiguration - - /** - * Converts literal schema definition to joi schema object (or returns the same back if already a joi schema object). - */ - compile(schema: SchemaLike, options?: CompileOptions): Schema - - /** - * Checks if the provided preferences are valid. - * - * Throws an exception if the prefs object is invalid. - * - * The method is provided to perform inputs validation for the `any.validate()` and `any.validateAsync()` methods. - * Validation is not performed automatically for performance reasons. Instead, manually validate the preferences passed once and reuse. - */ - checkPreferences(prefs: ValidationOptions): void - - /** - * Creates a custom validation schema. - */ - custom(fn: CustomValidator, description?: string): Schema - - /** - * Creates a new Joi instance that will apply defaults onto newly created schemas - * through the use of the fn function that takes exactly one argument, the schema being created. - * - * @param fn - The function must always return a schema, even if untransformed. - */ - defaults(fn: SchemaFunction): PluginOptionsSchemaJoi - - /** - * Generates a dynamic expression using a template string. - */ - expression(template: string, options?: ReferenceOptions): any - - /** - * Creates a new Joi instance customized with the extension(s) you provide included. - */ - extend(...extensions: Array): any - - /** - * Creates a reference that when resolved, is used as an array of values to match against the rule. - */ - in(ref: string, options?: ReferenceOptions): Reference - - /** - * Checks whether or not the provided argument is an instance of ValidationError - */ - isError(error: any): error is ValidationError - - /** - * Checks whether or not the provided argument is an expression. - */ - isExpression(expression: any): boolean - - /** - * Checks whether or not the provided argument is a reference. It's especially useful if you want to post-process error messages. - */ - isRef(ref: any): ref is Reference - - /** - * Checks whether or not the provided argument is a joi schema. - */ - isSchema(schema: any, options?: IsSchemaOptions): boolean - - /** - * A special value used with `any.allow()`, `any.invalid()`, and `any.valid()` as the first value to reset any previously set values. - */ - override: symbol - - /** - * Generates a reference to the value of the named key. - */ - ref(key: string, options?: ReferenceOptions): Reference - - /** - * Returns an object where each key is a plain joi schema type. - * Useful for creating type shortcuts using deconstruction. - * Note that the types are already formed and do not need to be called as functions (e.g. `string`, not `string()`). - */ - types(): { - alternatives: AlternativesSchema - any: AnySchema - array: ArraySchema - binary: BinarySchema - boolean: BooleanSchema - date: DateSchema - function: FunctionSchema - link: LinkSchema - number: NumberSchema - object: ObjectSchema - string: StringSchema - symbol: SymbolSchema - } - - /** - * Generates a dynamic expression using a template string. - */ - x(template: string, options?: ReferenceOptions): any - - // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- - // Below are undocumented APIs. use at your own risk - // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- - - /** - * Whitelists a value - */ - allow(...values: any[]): Schema - - /** - * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed. - */ - valid(...values: any[]): Schema - equal(...values: any[]): Schema - - /** - * Blacklists a value - */ - invalid(...values: any[]): Schema - disallow(...values: any[]): Schema - not(...values: any[]): Schema - - /** - * Marks a key as required which will not allow undefined as value. All keys are optional by default. - */ - required(): Schema - - /** - * Alias of `required`. - */ - exist(): Schema - - /** - * Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default. - */ - optional(): Schema - - /** - * Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys. - */ - forbidden(): Schema - - /** - * Overrides the global validate() options for the current key and any sub-key. - */ - preferences(options: ValidationOptions): Schema - - /** - * Overrides the global validate() options for the current key and any sub-key. - */ - prefs(options: ValidationOptions): Schema - - /** - * Converts the type into an alternatives type where the conditions are merged into the type definition where: - */ - when(ref: string | Reference, options: WhenOptions): AlternativesSchema - when(ref: Schema, options: WhenSchemaOptions): AlternativesSchema - - /** - * Unsure, maybe alias for `compile`? - */ - build(...args: any[]): any - - /** - * Unsure, maybe alias for `preferences`? - */ - options(...args: any[]): any - - /** - * Unsure, maybe leaked from `@hapi/lab/coverage/initialize` - */ - trace(...args: any[]): any - untrace(...args: any[]): any -} diff --git a/packages/gatsby-plugin-utils/src/validate.ts b/packages/gatsby-plugin-utils/src/validate.ts index 97e51c8b0f76c..85048793281d2 100644 --- a/packages/gatsby-plugin-utils/src/validate.ts +++ b/packages/gatsby-plugin-utils/src/validate.ts @@ -1,7 +1,7 @@ -import { BaseValidationOptions } from "joi" -import { ObjectSchema } from "./utils/plugin-options-schema-joi-type" +import { ValidationOptions, ObjectSchema } from "joi" +import { IPluginInfoOptions } from "gatsby/dist/bootstrap/load-plugins/types" -const validationOptions: BaseValidationOptions = { +const validationOptions: ValidationOptions = { // Show all errors at once, rather than only the first one every time abortEarly: false, cache: true, @@ -11,19 +11,19 @@ interface IOptions { validateExternalRules?: boolean } -export async function validateOptionsSchema( +export async function validateOptionsSchema( pluginSchema: ObjectSchema, - pluginOptions: PluginOptions, - options: IOptions = {} -): Promise { - if (options.validateExternalRules === false) { - const result = pluginSchema.validate(pluginOptions, { - ...validationOptions, - externals: false, - }) - if (result.error) throw result.error - return result.value + pluginOptions: IPluginInfoOptions, + options: IOptions = { + validateExternalRules: true, } +): Promise { + const { validateExternalRules } = options - return pluginSchema.validateAsync(pluginOptions, validationOptions) + const { value } = await pluginSchema.validateAsync(pluginOptions, { + ...validationOptions, + externals: validateExternalRules, + }) + + return value } diff --git a/packages/gatsby/src/bootstrap/load-plugins/validate.ts b/packages/gatsby/src/bootstrap/load-plugins/validate.ts index dff38403c156e..a56f3a2535bdf 100644 --- a/packages/gatsby/src/bootstrap/load-plugins/validate.ts +++ b/packages/gatsby/src/bootstrap/load-plugins/validate.ts @@ -197,16 +197,23 @@ export async function validatePluginOptions({ } try { - // All plugins have "plugins: []"" added to their options in load.ts, even if they - // do not have subplugins. We add plugins to the schema if it does not exist already - // to make sure they pass validation. + if (typeof plugin.pluginOptions === `undefined`) { + return null + } + if (!optionsSchema.describe().keys.plugins) { + // All plugins have "plugins: []"" added to their options in load.ts, even if they + // do not have subplugins. We add plugins to the schema if it does not exist already + // to make sure they pass validation. optionsSchema = optionsSchema.append({ plugins: Joi.array().length(0), }) } - await validateOptionsSchema(optionsSchema, plugin.pluginOptions) + plugin.pluginOptions = await validateOptionsSchema( + optionsSchema, + plugin.pluginOptions + ) } catch (error) { if (error instanceof Joi.ValidationError) { reporter.error({ From fba19f9c8275e3621926cd7571e7d6284040afdc Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Sat, 10 Oct 2020 22:41:42 -0700 Subject: [PATCH 2/9] fix: add missing comment From 0d3701be5a145a3217382656b863c27cd3455c95 Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Sat, 10 Oct 2020 22:42:13 -0700 Subject: [PATCH 3/9] fix: add missing comment --- packages/gatsby-plugin-utils/src/joi.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-plugin-utils/src/joi.ts b/packages/gatsby-plugin-utils/src/joi.ts index aebe391fcbb03..f10145965ffe3 100644 --- a/packages/gatsby-plugin-utils/src/joi.ts +++ b/packages/gatsby-plugin-utils/src/joi.ts @@ -1,7 +1,16 @@ import joi from "joi" import { Root } from "joi" -export type GatsbyPluginOptionsJoi = Root +export interface GatsbyPluginOptionsJoi extends Root { + // see note from @mxstbr on line 21 in rules + // /** + // * Specifies that a value should be stored in a .env file with ${name} + // * instead of inlined into the gatsby-config.js + // * @param name - string + // */ + // dotenv(name: string): this + +} export const Joi: GatsbyPluginOptionsJoi = joi.extend({ // This tells Joi to extend _all_ types with .dotenv(), see @@ -26,3 +35,5 @@ export const Joi: GatsbyPluginOptionsJoi = joi.extend({ // }, }, }) + + From de892c0fbac60baf5ed527699fac266dbb3fc496 Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Sat, 10 Oct 2020 23:00:02 -0700 Subject: [PATCH 4/9] fix: move gatsby to peer dep --- packages/gatsby-plugin-utils/package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-plugin-utils/package.json b/packages/gatsby-plugin-utils/package.json index ea47daebb8c59..7d662974c72c1 100644 --- a/packages/gatsby-plugin-utils/package.json +++ b/packages/gatsby-plugin-utils/package.json @@ -28,10 +28,12 @@ "@babel/core": "^7.11.6", "babel-preset-gatsby-package": "^0.5.3", "cross-env": "^7.0.2", - "gatsby": "^2.24.73", "rimraf": "^3.0.2", "typescript": "^3.9.5" }, + "peerDependencies": { + "gatsby": "^2.24.73" + }, "files": [ "dist/", "src/" @@ -39,4 +41,4 @@ "engines": { "node": ">=10.13.0" } -} +} \ No newline at end of file From b20d463e7a84f21cf3d7743d0b972ec2360244c5 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Fri, 16 Oct 2020 11:28:46 +0200 Subject: [PATCH 5/9] Undo Joi change --- .../__tests__/test-plugin-options-schema.ts | 2 +- packages/gatsby-plugin-utils/src/joi.ts | 18 +- .../utils/plugin-options-schema-joi-type.ts | 2257 +++++++++++++++++ packages/gatsby-plugin-utils/src/validate.ts | 3 +- 4 files changed, 2263 insertions(+), 17 deletions(-) create mode 100644 packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts diff --git a/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts b/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts index 53ea74c384cac..c016f409e72fe 100644 --- a/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts +++ b/packages/gatsby-plugin-utils/src/__tests__/test-plugin-options-schema.ts @@ -1,5 +1,5 @@ import { testPluginOptionsSchema } from "../test-plugin-options-schema" -import { ObjectSchema } from "joi" +import { ObjectSchema } from "../joi" describe(`testPluginOptionsSchema`, () => { it(`should partially validate one value of a schema`, () => { diff --git a/packages/gatsby-plugin-utils/src/joi.ts b/packages/gatsby-plugin-utils/src/joi.ts index f10145965ffe3..c2072a92bb61b 100644 --- a/packages/gatsby-plugin-utils/src/joi.ts +++ b/packages/gatsby-plugin-utils/src/joi.ts @@ -1,18 +1,8 @@ import joi from "joi" -import { Root } from "joi" +import { PluginOptionsSchemaJoi } from "./utils/plugin-options-schema-joi-type" -export interface GatsbyPluginOptionsJoi extends Root { - // see note from @mxstbr on line 21 in rules - // /** - // * Specifies that a value should be stored in a .env file with ${name} - // * instead of inlined into the gatsby-config.js - // * @param name - string - // */ - // dotenv(name: string): this - -} - -export const Joi: GatsbyPluginOptionsJoi = joi.extend({ +export * from "./utils/plugin-options-schema-joi-type" +export const Joi: PluginOptionsSchemaJoi = joi.extend({ // This tells Joi to extend _all_ types with .dotenv(), see // https://github.com/sideway/joi/commit/03adf22eb1f06c47d1583617093edee3a96b3873 // @ts-ignore Joi types weren't updated with that commit, PR: https://github.com/sideway/joi/pull/2477 @@ -35,5 +25,3 @@ export const Joi: GatsbyPluginOptionsJoi = joi.extend({ // }, }, }) - - diff --git a/packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts b/packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts new file mode 100644 index 0000000000000..c56386f79d299 --- /dev/null +++ b/packages/gatsby-plugin-utils/src/utils/plugin-options-schema-joi-type.ts @@ -0,0 +1,2257 @@ +/* eslint-disable */ +// The following definitions have been copied (almost) as-is from: +// https://github.com/sideway/joi/tree/master/lib/index.d.ts +// The only change @mxstbr made was to add support for our custom +// .dotenv extension to AnySchema. + +type Types = + | "any" + | "alternatives" + | "array" + | "boolean" + | "binary" + | "date" + | "function" + | "link" + | "number" + | "object" + | "string" + | "symbol" + +type BasicType = boolean | number | string | any[] | object | null + +type LanguageMessages = Record + +type PresenceMode = "optional" | "required" | "forbidden" + +interface ErrorFormattingOptions { + /** + * when true, error message templates will escape special characters to HTML entities, for security purposes. + * + * @default false + */ + escapeHtml?: boolean + /** + * defines the value used to set the label context variable. + */ + label?: "path" | "key" | false + /** + * The preferred language code for error messages. + * The value is matched against keys at the root of the messages object, and then the error code as a child key of that. + * Can be a reference to the value, global context, or local context which is the root value passed to the validation function. + * + * Note that references to the value are usually not what you want as they move around the value structure relative to where the error happens. + * Instead, either use the global context, or the absolute value (e.g. `Joi.ref('/variable')`) + */ + language?: keyof LanguageMessages + /** + * when false, skips rendering error templates. Useful when error messages are generated elsewhere to save processing time. + * + * @default true + */ + render?: boolean + /** + * when true, the main error will possess a stack trace, otherwise it will be disabled. + * Defaults to false for performances reasons. Has no effect on platforms other than V8/node.js as it uses the Stack trace API. + * + * @default false + */ + stack?: boolean + /** + * overrides the way values are wrapped (e.g. `[]` arround arrays, `""` around labels). + * Each key can be set to a string with one (same character before and after the value) or two characters (first character + * before and second character after), or `false` to disable wrapping. + */ + wrap?: { + /** + * the characters used around `{#label}` references. Defaults to `'"'`. + * + * @default '"' + */ + label?: string | false + + /** + * the characters used around array avlues. Defaults to `'[]'` + * + * @default '[]' + */ + array?: string | false + } +} + +interface BaseValidationOptions { + /** + * when true, stops validation on the first error, otherwise returns all the errors found. + * + * @default true + */ + abortEarly?: boolean + /** + * when true, allows object to contain unknown keys which are ignored. + * + * @default false + */ + allowUnknown?: boolean + /** + * when true, schema caching is enabled (for schemas with explicit caching rules). + * + * @default false + */ + cache?: boolean + /** + * provides an external data set to be used in references + */ + context?: Context + /** + * when true, attempts to cast values to the required types (e.g. a string to a number). + * + * @default true + */ + convert?: boolean + /** + * sets the string format used when converting dates to strings in error messages and casting. + * + * @default 'iso' + */ + dateFormat?: "date" | "iso" | "string" | "time" | "utc" + /** + * when true, valid results and throw errors are decorated with a debug property which includes an array of the validation steps used to generate the returned result. + * + * @default false + */ + debug?: boolean + /** + * error formatting settings. + */ + errors?: ErrorFormattingOptions + /** + * if false, the external rules set with `any.external()` are ignored, which is required to ignore any external validations in synchronous mode (or an exception is thrown). + * + * @default true + */ + externals?: boolean + /** + * when true, do not apply default values. + * + * @default false + */ + noDefaults?: boolean + /** + * when true, inputs are shallow cloned to include non-enumerables properties. + * + * @default false + */ + nonEnumerables?: boolean + /** + * sets the default presence requirements. Supported modes: 'optional', 'required', and 'forbidden'. + * + * @default 'optional' + */ + presence?: PresenceMode + /** + * when true, ignores unknown keys with a function value. + * + * @default false + */ + skipFunctions?: boolean + /** + * remove unknown elements from objects and arrays. + * - when true, all unknown elements will be removed + * - when an object: + * - objects - set to true to remove unknown keys from objects + * + * @default false + */ + stripUnknown?: boolean | { arrays?: boolean; objects?: boolean } +} + +interface ValidationOptions extends BaseValidationOptions { + /** + * overrides individual error messages. Defaults to no override (`{}`). + * Messages use the same rules as templates. + * Variables in double braces `{{var}}` are HTML escaped if the option `errors.escapeHtml` is set to true. + * + * @default {} + */ + messages?: LanguageMessages +} + +interface AsyncValidationOptions extends ValidationOptions { + /** + * when true, warnings are returned alongside the value (i.e. `{ value, warning }`). + * + * @default false + */ + warnings?: boolean +} + +interface LanguageMessageTemplate { + source: string + rendered: string +} + +interface ErrorValidationOptions extends BaseValidationOptions { + messages?: Record +} + +interface RenameOptions { + /** + * if true, does not delete the old key name, keeping both the new and old keys in place. + * + * @default false + */ + alias?: boolean + /** + * if true, allows renaming multiple keys to the same destination where the last rename wins. + * + * @default false + */ + multiple?: boolean + /** + * if true, allows renaming a key over an existing key. + * + * @default false + */ + override?: boolean + /** + * if true, skip renaming of a key if it's undefined. + * + * @default false + */ + ignoreUndefined?: boolean +} + +interface TopLevelDomainOptions { + /** + * - `true` to use the IANA list of registered TLDs. This is the default value. + * - `false` to allow any TLD not listed in the `deny` list, if present. + * - A `Set` or array of the allowed TLDs. Cannot be used together with `deny`. + */ + allow?: Set | string[] | boolean + /** + * - A `Set` or array of the forbidden TLDs. Cannot be used together with a custom `allow` list. + */ + deny?: Set | string[] +} + +interface HierarchySeparatorOptions { + /** + * overrides the default `.` hierarchy separator. Set to false to treat the key as a literal value. + * + * @default '.' + */ + separator?: string | false +} + +interface EmailOptions { + /** + * If `true`, Unicode characters are permitted + * + * @default true + */ + allowUnicode?: boolean + /** + * if `true`, ignore invalid email length errors. + * + * @default false + */ + ignoreLength?: boolean + /** + * if true, allows multiple email addresses in a single string, separated by , or the separator characters. + * + * @default false + */ + multiple?: boolean + /** + * when multiple is true, overrides the default , separator. String can be a single character or multiple separator characters. + * + * @default ',' + */ + separator?: string | string[] + /** + * Options for TLD (top level domain) validation. By default, the TLD must be a valid name listed on the [IANA registry](http://data.iana.org/TLD/tlds-alpha-by-domain.txt) + * + * @default { allow: true } + */ + tlds?: TopLevelDomainOptions | false + /** + * Number of segments required for the domain. Be careful since some domains, such as `io`, directly allow email. + * + * @default 2 + */ + minDomainSegments?: number +} + +interface DomainOptions { + /** + * If `true`, Unicode characters are permitted + * + * @default true + */ + allowUnicode?: boolean + + /** + * Options for TLD (top level domain) validation. By default, the TLD must be a valid name listed on the [IANA registry](http://data.iana.org/TLD/tlds-alpha-by-domain.txt) + * + * @default { allow: true } + */ + tlds?: TopLevelDomainOptions | false + /** + * Number of segments required for the domain. + * + * @default 2 + */ + minDomainSegments?: number +} + +interface HexOptions { + /** + * hex decoded representation must be byte aligned. + * @default false + */ + byteAligned?: boolean +} + +interface IpOptions { + /** + * One or more IP address versions to validate against. Valid values: ipv4, ipv6, ipvfuture + */ + version?: string | string[] + /** + * Used to determine if a CIDR is allowed or not. Valid values: optional, required, forbidden + */ + cidr?: PresenceMode +} + +type GuidVersions = "uuidv1" | "uuidv2" | "uuidv3" | "uuidv4" | "uuidv5" + +interface GuidOptions { + version: GuidVersions[] | GuidVersions +} + +interface UriOptions { + /** + * Specifies one or more acceptable Schemes, should only include the scheme name. + * Can be an Array or String (strings are automatically escaped for use in a Regular Expression). + */ + scheme?: string | RegExp | Array + /** + * Allow relative URIs. + * + * @default false + */ + allowRelative?: boolean + /** + * Restrict only relative URIs. + * + * @default false + */ + relativeOnly?: boolean + /** + * Allows unencoded square brackets inside the query string. + * This is NOT RFC 3986 compliant but query strings like abc[]=123&abc[]=456 are very common these days. + * + * @default false + */ + allowQuerySquareBrackets?: boolean + /** + * Validate the domain component using the options specified in `string.domain()`. + */ + domain?: DomainOptions +} + +interface DataUriOptions { + /** + * optional parameter defaulting to true which will require `=` padding if true or make padding optional if false + * + * @default true + */ + paddingRequired?: boolean +} + +interface Base64Options extends Pick { + /** + * if true, uses the URI-safe base64 format which replaces `+` with `-` and `\` with `_`. + * + * @default false + */ + urlSafe?: boolean +} + +interface SwitchCases { + /** + * the required condition joi type. + */ + is: SchemaLike + /** + * the alternative schema type if the condition is true. + */ + then: SchemaLike +} + +interface SwitchDefault { + /** + * the alternative schema type if no cases matched. + * Only one otherwise statement is allowed in switch as the last array item. + */ + otherwise: SchemaLike +} + +interface WhenOptions { + /** + * the required condition joi type. + */ + is?: SchemaLike + + /** + * the negative version of `is` (`then` and `otherwise` have reverse + * roles). + */ + not?: SchemaLike + + /** + * the alternative schema type if the condition is true. Required if otherwise or switch are missing. + */ + then?: SchemaLike + + /** + * the alternative schema type if the condition is false. Required if then or switch are missing. + */ + otherwise?: SchemaLike + + /** + * the list of cases. Required if then is missing. Required if then or otherwise are missing. + */ + switch?: Array + + /** + * whether to stop applying further conditions if the condition is true. + */ + break?: boolean +} + +interface WhenSchemaOptions { + /** + * the alternative schema type if the condition is true. Required if otherwise is missing. + */ + then?: SchemaLike + /** + * the alternative schema type if the condition is false. Required if then is missing. + */ + otherwise?: SchemaLike +} + +interface Cache { + /** + * Add an item to the cache. + * + * Note that key and value can be anything including objects, array, etc. + */ + set(key: any, value: any): void + + /** + * Retrieve an item from the cache. + * + * Note that key and value can be anything including objects, array, etc. + */ + get(key: any): any +} +interface CacheProvisionOptions { + /** + * number of items to store in the cache before the least used items are dropped. + * + * @default 1000 + */ + max: number +} + +interface CacheConfiguration { + /** + * Provisions a simple LRU cache for caching simple inputs (`undefined`, `null`, strings, numbers, and booleans). + */ + provision(options?: CacheProvisionOptions): void +} + +interface CompileOptions { + /** + * If true and the provided schema is (or contains parts) using an older version of joi, will return a compiled schema that is compatible with the older version. + * If false, the schema is always compiled using the current version and if older schema components are found, an error is thrown. + */ + legacy: boolean +} + +interface IsSchemaOptions { + /** + * If true, will identify schemas from older versions of joi, otherwise will throw an error. + * + * @default false + */ + legacy: boolean +} + +interface ReferenceOptions extends HierarchySeparatorOptions { + /** + * a function with the signature `function(value)` where `value` is the resolved reference value and the return value is the adjusted value to use. + * Note that the adjust feature will not perform any type validation on the adjusted value and it must match the value expected by the rule it is used in. + * Cannot be used with `map`. + * + * @example `(value) => value + 5` + */ + adjust?: (value: any) => any + + /** + * an array of array pairs using the format `[[key, value], [key, value]]` used to maps the resolved reference value to another value. + * If the resolved value is not in the map, it is returned as-is. + * Cannot be used with `adjust`. + */ + map?: Array<[any, any]> + + /** + * overrides default prefix characters. + */ + prefix?: { + /** + * references to the globally provided context preference. + * + * @default '$' + */ + global?: string + + /** + * references to error-specific or rule specific context. + * + * @default '#' + */ + local?: string + + /** + * references to the root value being validated. + * + * @default '/' + */ + root?: string + } + + /** + * If set to a number, sets the reference relative starting point. + * Cannot be combined with separator prefix characters. + * Defaults to the reference key prefix (or 1 if none present) + */ + ancestor?: number + + /** + * creates an in-reference. + */ + in?: boolean + + /** + * when true, the reference resolves by reaching into maps and sets. + */ + iterables?: boolean +} + +interface StringRegexOptions { + /** + * optional pattern name. + */ + name?: string + + /** + * when true, the provided pattern will be disallowed instead of required. + * + * @default false + */ + invert?: boolean +} + +interface RuleOptions { + /** + * if true, the rules will not be replaced by the same unique rule later. + * + * For example, `Joi.number().min(1).rule({ keep: true }).min(2)` will keep both `min()` rules instead of the later rule overriding the first. + * + * @default false + */ + keep?: boolean + + /** + * a single message string or a messages object where each key is an error code and corresponding message string as value. + * + * The object is the same as the messages used as an option in `any.validate()`. + * The strings can be plain messages or a message template. + */ + message?: string | LanguageMessages + + /** + * if true, turns any error generated by the ruleset to warnings. + */ + warn?: boolean +} + +interface ErrorReport extends Error { + code: string + flags: Record + path: string[] + prefs: ErrorValidationOptions + messages: LanguageMessages + state: State + value: any +} + +interface ValidationError extends Error { + name: "ValidationError" + + isJoi: boolean + + /** + * array of errors. + */ + details: ValidationErrorItem[] + + /** + * function that returns a string with an annotated version of the object pointing at the places where errors occurred. + * + * NOTE: This method does not exist in browser builds of Joi + * + * @param stripColors - if truthy, will strip the colors out of the output. + */ + annotate(stripColors?: boolean): string + + _object: any +} + +interface ValidationErrorItem { + message: string + path: Array + type: string + context?: Context +} + +type ValidationErrorFunction = ( + errors: ErrorReport[] +) => string | ValidationErrorItem | Error + +interface ValidationResult { + error?: ValidationError + errors?: ValidationError + warning?: ValidationError + value: any +} + +interface CreateErrorOptions { + flags?: boolean + messages?: LanguageMessages +} + +interface ModifyOptions { + each?: boolean + once?: boolean + ref?: boolean + schema?: boolean +} + +interface MutateRegisterOptions { + family?: any + key?: any +} + +interface SetFlagOptions { + clone: boolean +} + +interface CustomHelpers { + schema: ExtensionBoundSchema + state: State + prefs: ValidationOptions + original: V + warn: (code: string, local?: Context) => void + error: (code: string, local?: Context) => ErrorReport + message: (messages: LanguageMessages, local?: Context) => ErrorReport +} + +type CustomValidator = (value: V, helpers: CustomHelpers) => V + +type ExternalValidationFunction = (value: any) => any + +type SchemaLikeWithoutArray = + | string + | number + | boolean + | null + | Schema + | SchemaMap +type SchemaLike = SchemaLikeWithoutArray | object + +type SchemaMap = { + [key in keyof TSchema]?: SchemaLike | SchemaLike[] +} + +export type Schema = + | AnySchema + | ArraySchema + | AlternativesSchema + | BinarySchema + | BooleanSchema + | DateSchema + | FunctionSchema + | NumberSchema + | ObjectSchema + | StringSchema + | LinkSchema + | SymbolSchema + +type SchemaFunction = (schema: Schema) => Schema + +interface AddRuleOptions { + name: string + args?: { + [key: string]: any + } +} + +interface GetRuleOptions { + args?: Record + method?: string + name: string + operator?: string +} + +interface SchemaInternals { + /** + * Parent schema object. + */ + $_super: Schema + + /** + * Terms of current schema. + */ + $_terms: Record + + /** + * Adds a rule to current validation schema. + */ + $_addRule(rule: string | AddRuleOptions): Schema + + /** + * Internally compiles schema. + */ + $_compile(schema: SchemaLike, options?: CompileOptions): Schema + + /** + * Creates a joi error object. + */ + $_createError( + code: string, + value: any, + context: Context, + state: State, + prefs: ValidationOptions, + options?: CreateErrorOptions + ): Err + + /** + * Get value from given flag. + */ + $_getFlag(name: string): any + + /** + * Retrieve some rule configuration. + */ + $_getRule(name: string): GetRuleOptions | undefined + + $_mapLabels(path: string | string[]): string + + /** + * Returns true if validations runs fine on given value. + */ + $_match(value: any, state: State, prefs: ValidationOptions): boolean + + $_modify(options?: ModifyOptions): Schema + + /** + * Resets current schema. + */ + $_mutateRebuild(): this + + $_mutateRegister(schema: Schema, options?: MutateRegisterOptions): void + + /** + * Get value from given property. + */ + $_property(name: string): any + + /** + * Get schema at given path. + */ + $_reach(path: string[]): Schema + + /** + * Get current schema root references. + */ + $_rootReferences(): any + + /** + * Set flag to given value. + */ + $_setFlag(flag: string, value: any, options?: SetFlagOptions): void + + /** + * Runs internal validations against given value. + */ + $_validate( + value: any, + state: State, + prefs: ValidationOptions + ): ValidationResult +} + +interface AnySchema extends SchemaInternals { + /** + * Flags of current schema. + */ + _flags: Record + + /** + * Starts a ruleset in order to apply multiple rule options. The set ends when `rule()`, `keep()`, `message()`, or `warn()` is called. + */ + $: this + + /** + * Starts a ruleset in order to apply multiple rule options. The set ends when `rule()`, `keep()`, `message()`, or `warn()` is called. + */ + ruleset: this + + type?: Types | string + + /** + * Whitelists a value + */ + allow(...values: any[]): this + + /** + * Assign target alteration options to a schema that are applied when `any.tailor()` is called. + * @param targets - an object where each key is a target name, and each value is a function that takes an schema and returns an schema. + */ + alter(targets: Record): this + + /** + * By default, some Joi methods to function properly need to rely on the Joi instance they are attached to because + * they use `this` internally. + * So `Joi.string()` works but if you extract the function from it and call `string()` it won't. + * `bind()` creates a new Joi instance where all the functions relying on `this` are bound to the Joi instance. + */ + bind(): this + + /** + * Adds caching to the schema which will attempt to cache the validation results (success and failures) of incoming inputs. + * If no cache is passed, a default cache is provisioned by using `cache.provision()` internally. + */ + cache(cache?: Cache): this + + /** + * Casts the validated value to the specified type. + */ + cast(to: "map" | "number" | "set" | "string"): this + + /** + * Returns a new type that is the result of adding the rules of one type to another. + */ + concat(schema: this): this + + /** + * Adds a custom validation function. + */ + custom(fn: CustomValidator, description?: string): this + + /** + * Sets a default value if the original value is `undefined` where: + * @param value - the default value. One of: + * - a literal value (string, number, object, etc.) + * - a [references](#refkey-options) + * - a function which returns the default value using the signature `function(parent, helpers)` where: + * - `parent` - a clone of the object containing the value being validated. Note that since specifying a + * `parent` ragument performs cloning, do not declare format arguments if you are not using them. + * - `helpers` - same as thsoe described in [`any.custom()`](anycustomermethod_description) + * + * When called without any `value` on an object schema type, a default value will be automatically generated + * based on the default values of the object keys. + * + * Note that if value is an object, any changes to the object after `default()` is called will change the + * reference and any future assignment. + */ + default( + value?: + | BasicType + | Reference + | ((parent: any, helpers: CustomHelpers) => BasicType | Reference) + ): this + + /** + * Returns a plain object representing the schema's rules and properties + */ + describe(): Description + + /** + * Annotates the key + */ + description(desc: string): this + + /** + * Disallows values. + */ + disallow(...values: any[]): this + + /** + * Specifies that a value should be stored in a .env file with ${name} + * instead of inlined into the gatsby-config.js + * @param name - string + */ + dotenv(name: string): this + + /** + * Considers anything that matches the schema to be empty (undefined). + * @param schema - any object or joi schema to match. An undefined schema unsets that rule. + */ + empty(schema?: SchemaLike): this + + /** + * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed. + */ + equal(...values: any[]): this + + /** + * Overrides the default joi error with a custom error if the rule fails where: + * @param err - can be: + * an instance of `Error` - the override error. + * a `function(errors)`, taking an array of errors as argument, where it must either: + * return a `string` - substitutes the error message with this text + * return a single ` object` or an `Array` of it, where: + * `type` - optional parameter providing the type of the error (eg. `number.min`). + * `message` - optional parameter if `template` is provided, containing the text of the error. + * `template` - optional parameter if `message` is provided, containing a template string, using the same format as usual joi language errors. + * `context` - optional parameter, to provide context to your error if you are using the `template`. + * return an `Error` - same as when you directly provide an `Error`, but you can customize the error message based on the errors. + * + * Note that if you provide an `Error`, it will be returned as-is, unmodified and undecorated with any of the + * normal joi error properties. If validation fails and another error is found before the error + * override, that error will be returned and the override will be ignored (unless the `abortEarly` + * option has been set to `false`). + */ + error(err: Error | ValidationErrorFunction): this + + /** + * Annotates the key with an example value, must be valid. + */ + example(value: any, options?: { override: boolean }): this + + /** + * Marks a key as required which will not allow undefined as value. All keys are optional by default. + */ + exist(): this + + /** + * Adds an external validation rule. + * + * Note that external validation rules are only called after the all other validation rules for the entire schema (from the value root) are checked. + * This means that any changes made to the value by the external rules are not available to any other validation rules during the non-external validation phase. + * If schema validation failed, no external validation rules are called. + */ + external(method: ExternalValidationFunction, description?: string): this + + /** + * Returns a sub-schema based on a path of object keys or schema ids. + * + * @param path - a dot `.` separated path string or a pre-split array of path keys. The keys must match the sub-schema id or object key (if no id was explicitly set). + */ + extract(path: string | string[]): Schema + + /** + * Sets a failover value if the original value fails passing validation. + * + * @param value - the failover value. value supports references. value may be assigned a function which returns the default value. + * + * If value is specified as a function that accepts a single parameter, that parameter will be a context object that can be used to derive the resulting value. + * Note that if value is an object, any changes to the object after `failover()` is called will change the reference and any future assignment. + * Use a function when setting a dynamic value (e.g. the current time). + * Using a function with a single argument performs some internal cloning which has a performance impact. + * If you do not need access to the context, define the function without any arguments. + */ + failover(value: any): this + + /** + * Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys. + */ + forbidden(): this + + /** + * Returns a new schema where each of the path keys listed have been modified. + * + * @param key - an array of key strings, a single key string, or an array of arrays of pre-split key strings. + * @param adjuster - a function which must return a modified schema. + */ + fork(key: string | string[] | string[][], adjuster: SchemaFunction): this + + /** + * Sets a schema id for reaching into the schema via `any.extract()`. + * If no id is set, the schema id defaults to the object key it is associated with. + * If the schema is used in an array or alternatives type and no id is set, the schema in unreachable. + */ + id(name?: string): this + + /** + * Disallows values. + */ + invalid(...values: any[]): this + + /** + * Same as `rule({ keep: true })`. + * + * Note that `keep()` will terminate the current ruleset and cannot be followed by another rule option. + * Use `rule()` to apply multiple rule options. + */ + keep(): this + + /** + * Overrides the key name in error messages. + */ + label(name: string): this + + /** + * Same as `rule({ message })`. + * + * Note that `message()` will terminate the current ruleset and cannot be followed by another rule option. + * Use `rule()` to apply multiple rule options. + */ + message(message: string): this + + /** + * Same as `any.prefs({ messages })`. + * Note that while `any.message()` applies only to the last rule or ruleset, `any.messages()` applies to the entire schema. + */ + messages(messages: LanguageMessages): this + + /** + * Attaches metadata to the key. + */ + meta(meta: object): this + + /** + * Disallows values. + */ + not(...values: any[]): this + + /** + * Annotates the key + */ + note(...notes: string[]): this + + /** + * Requires the validated value to match of the provided `any.allow()` values. + * It has not effect when called together with `any.valid()` since it already sets the requirements. + * When used with `any.allow()` it converts it to an `any.valid()`. + */ + only(): this + + /** + * Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default. + */ + optional(): this + + /** + * Overrides the global validate() options for the current key and any sub-key. + */ + options(options: ValidationOptions): this + + /** + * Overrides the global validate() options for the current key and any sub-key. + */ + prefs(options: ValidationOptions): this + + /** + * Overrides the global validate() options for the current key and any sub-key. + */ + preferences(options: ValidationOptions): this + + /** + * Sets the presence mode for the schema. + */ + presence(mode: PresenceMode): this + + /** + * Outputs the original untouched value instead of the casted value. + */ + raw(enabled?: boolean): this + + /** + * Marks a key as required which will not allow undefined as value. All keys are optional by default. + */ + required(): this + + /** + * Applies a set of rule options to the current ruleset or last rule added. + * + * When applying rule options, the last rule (e.g. `min()`) is used unless there is an active ruleset defined (e.g. `$.min().max()`) + * in which case the options are applied to all the provided rules. + * Once `rule()` is called, the previous rules can no longer be modified and any active ruleset is terminated. + * + * Rule modifications can only be applied to supported rules. + * Most of the `any` methods do not support rule modifications because they are implemented using schema flags (e.g. `required()`) or special + * internal implementation (e.g. `valid()`). + * In those cases, use the `any.messages()` method to override the error codes for the errors you want to customize. + */ + rule(options: RuleOptions): this + + /** + * Registers a schema to be used by decendents of the current schema in named link references. + */ + shared(ref: Schema): this + + /** + * Sets the options.convert options to false which prevent type casting for the current key and any child keys. + */ + strict(isStrict?: boolean): this + + /** + * Marks a key to be removed from a resulting object or array after validation. Used to sanitize output. + * @param [enabled=true] - if true, the value is stripped, otherwise the validated value is retained. Defaults to true. + */ + strip(enabled?: boolean): this + + /** + * Annotates the key + */ + tag(...tags: string[]): this + + /** + * Applies any assigned target alterations to a copy of the schema that were applied via `any.alter()`. + */ + tailor(targets: string | string[]): Schema + + /** + * Annotates the key with an unit name. + */ + unit(name: string): this + + /** + * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed. + */ + valid(...values: any[]): this + + /** + * Validates a value using the schema and options. + */ + validate(value: any, options?: ValidationOptions): ValidationResult + + /** + * Validates a value using the schema and options. + */ + validateAsync(value: any, options?: AsyncValidationOptions): Promise + + /** + * Same as `rule({ warn: true })`. + * Note that `warn()` will terminate the current ruleset and cannot be followed by another rule option. + * Use `rule()` to apply multiple rule options. + */ + warn(): this + + /** + * Generates a warning. + * When calling `any.validateAsync()`, set the `warning` option to true to enable warnings. + * Warnings are reported separately from errors alongside the result value via the warning key (i.e. `{ value, warning }`). + * Warning are always included when calling `any.validate()`. + */ + warning(code: string, context: Context): this + + /** + * Converts the type into an alternatives type where the conditions are merged into the type definition where: + */ + when(ref: string | Reference, options: WhenOptions): this + + /** + * Converts the type into an alternatives type where the conditions are merged into the type definition where: + */ + when(ref: Schema, options: WhenSchemaOptions): this +} + +interface Description { + type?: Types | string + label?: string + description?: string + flags?: object + notes?: string[] + tags?: string[] + meta?: any[] + example?: any[] + valids?: any[] + invalids?: any[] + unit?: string + options?: ValidationOptions + [key: string]: any +} + +interface Context { + [key: string]: any + key?: string + label?: string + value?: any +} + +interface State { + key?: string + path?: string + parent?: any + reference?: any + ancestors?: any + localize?(...args: any[]): State +} + +interface BooleanSchema extends AnySchema { + /** + * Allows for additional values to be considered valid booleans by converting them to false during validation. + * String comparisons are by default case insensitive, + * see `boolean.sensitive()` to change this behavior. + * @param values - strings, numbers or arrays of them + */ + falsy(...values: Array): this + + /** + * Allows the values provided to truthy and falsy as well as the "true" and "false" default conversion + * (when not in `strict()` mode) to be matched in a case insensitive manner. + */ + sensitive(enabled?: boolean): this + + /** + * Allows for additional values to be considered valid booleans by converting them to true during validation. + * String comparisons are by default case insensitive, see `boolean.sensitive()` to change this behavior. + * @param values - strings, numbers or arrays of them + */ + truthy(...values: Array): this +} + +interface NumberSchema extends AnySchema { + /** + * Specifies that the value must be greater than limit. + * It can also be a reference to another field. + */ + greater(limit: number | Reference): this + + /** + * Requires the number to be an integer (no floating point). + */ + integer(): this + + /** + * Specifies that the value must be less than limit. + * It can also be a reference to another field. + */ + less(limit: number | Reference): this + + /** + * Specifies the maximum value. + * It can also be a reference to another field. + */ + max(limit: number | Reference): this + + /** + * Specifies the minimum value. + * It can also be a reference to another field. + */ + min(limit: number | Reference): this + + /** + * Specifies that the value must be a multiple of base. + */ + multiple(base: number | Reference): this + + /** + * Requires the number to be negative. + */ + negative(): this + + /** + * Requires the number to be a TCP port, so between 0 and 65535. + */ + port(): this + + /** + * Requires the number to be positive. + */ + positive(): this + + /** + * Specifies the maximum number of decimal places where: + * @param limit - the maximum number of decimal places allowed. + */ + precision(limit: number): this + + /** + * Requires the number to be negative or positive. + */ + sign(sign: "positive" | "negative"): this + + /** + * Allows the number to be outside of JavaScript's safety range (Number.MIN_SAFE_INTEGER & Number.MAX_SAFE_INTEGER). + */ + unsafe(enabled?: any): this +} + +interface StringSchema extends AnySchema { + /** + * Requires the string value to only contain a-z, A-Z, and 0-9. + */ + alphanum(): this + + /** + * Requires the string value to be a valid base64 string; does not check the decoded value. + */ + base64(options?: Base64Options): this + + /** + * Sets the required string case. + */ + case(direction: "upper" | "lower"): this + + /** + * Requires the number to be a credit card number (Using Lunh Algorithm). + */ + creditCard(): this + + /** + * Requires the string value to be a valid data URI string. + */ + dataUri(options?: DataUriOptions): this + + /** + * Requires the string value to be a valid domain. + */ + domain(options?: DomainOptions): this + + /** + * Requires the string value to be a valid email address. + */ + email(options?: EmailOptions): this + + /** + * Requires the string value to be a valid GUID. + */ + guid(options?: GuidOptions): this + + /** + * Requires the string value to be a valid hexadecimal string. + */ + hex(options?: HexOptions): this + + /** + * Requires the string value to be a valid hostname as per RFC1123. + */ + hostname(): this + + /** + * Allows the value to match any whitelist of blacklist item in a case insensitive comparison. + */ + insensitive(): this + + /** + * Requires the string value to be a valid ip address. + */ + ip(options?: IpOptions): this + + /** + * Requires the string value to be in valid ISO 8601 date format. + */ + isoDate(): this + + /** + * Requires the string value to be in valid ISO 8601 duration format. + */ + isoDuration(): this + + /** + * Specifies the exact string length required + * @param limit - the required string length. It can also be a reference to another field. + * @param encoding - if specified, the string length is calculated in bytes using the provided encoding. + */ + length(limit: number | Reference, encoding?: string): this + + /** + * Requires the string value to be all lowercase. If the validation convert option is on (enabled by default), the string will be forced to lowercase. + */ + lowercase(): this + + /** + * Specifies the maximum number of string characters. + * @param limit - the maximum number of string characters allowed. It can also be a reference to another field. + * @param encoding - if specified, the string length is calculated in bytes using the provided encoding. + */ + max(limit: number | Reference, encoding?: string): this + + /** + * Specifies the minimum number string characters. + * @param limit - the minimum number of string characters required. It can also be a reference to another field. + * @param encoding - if specified, the string length is calculated in bytes using the provided encoding. + */ + min(limit: number | Reference, encoding?: string): this + + /** + * Requires the string value to be in a unicode normalized form. If the validation convert option is on (enabled by default), the string will be normalized. + * @param [form='NFC'] - The unicode normalization form to use. Valid values: NFC [default], NFD, NFKC, NFKD + */ + normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD"): this + + /** + * Defines a regular expression rule. + * @param pattern - a regular expression object the string value must match against. + * @param options - optional, can be: + * Name for patterns (useful with multiple patterns). Defaults to 'required'. + * An optional configuration object with the following supported properties: + * name - optional pattern name. + * invert - optional boolean flag. Defaults to false behavior. If specified as true, the provided pattern will be disallowed instead of required. + */ + pattern(pattern: RegExp, options?: string | StringRegexOptions): this + + /** + * Defines a regular expression rule. + * @param pattern - a regular expression object the string value must match against. + * @param options - optional, can be: + * Name for patterns (useful with multiple patterns). Defaults to 'required'. + * An optional configuration object with the following supported properties: + * name - optional pattern name. + * invert - optional boolean flag. Defaults to false behavior. If specified as true, the provided pattern will be disallowed instead of required. + */ + regex(pattern: RegExp, options?: string | StringRegexOptions): this + + /** + * Replace characters matching the given pattern with the specified replacement string where: + * @param pattern - a regular expression object to match against, or a string of which all occurrences will be replaced. + * @param replacement - the string that will replace the pattern. + */ + replace(pattern: RegExp | string, replacement: string): this + + /** + * Requires the string value to only contain a-z, A-Z, 0-9, and underscore _. + */ + token(): this + + /** + * Requires the string value to contain no whitespace before or after. If the validation convert option is on (enabled by default), the string will be trimmed. + * @param [enabled=true] - optional parameter defaulting to true which allows you to reset the behavior of trim by providing a falsy value. + */ + trim(enabled?: any): this + + /** + * Specifies whether the string.max() limit should be used as a truncation. + * @param [enabled=true] - optional parameter defaulting to true which allows you to reset the behavior of truncate by providing a falsy value. + */ + truncate(enabled?: boolean): this + + /** + * Requires the string value to be all uppercase. If the validation convert option is on (enabled by default), the string will be forced to uppercase. + */ + uppercase(): this + + /** + * Requires the string value to be a valid RFC 3986 URI. + */ + uri(options?: UriOptions): this + + /** + * Requires the string value to be a valid GUID. + */ + uuid(options?: GuidOptions): this +} + +interface SymbolSchema extends AnySchema { + // TODO: support number and symbol index + map( + iterable: + | Iterable<[string | number | boolean | symbol, symbol]> + | { [key: string]: symbol } + ): this +} + +interface ArraySortOptions { + /** + * @default 'ascending' + */ + order?: "ascending" | "descending" + by?: string | Reference +} + +interface ArrayUniqueOptions extends HierarchySeparatorOptions { + /** + * if true, undefined values for the dot notation string comparator will not cause the array to fail on uniqueness. + * + * @default false + */ + ignoreUndefined?: boolean +} + +type ComparatorFunction = (a: any, b: any) => boolean + +interface ArraySchema extends AnySchema { + /** + * Verifies that an assertion passes for at least one item in the array, where: + * `schema` - the validation rules required to satisfy the assertion. If the `schema` includes references, they are resolved against + * the array item being tested, not the value of the `ref` target. + */ + has(schema: SchemaLike): this + + /** + * List the types allowed for the array values. + * If a given type is .required() then there must be a matching item in the array. + * If a type is .forbidden() then it cannot appear in the array. + * Required items can be added multiple times to signify that multiple items must be found. + * Errors will contain the number of items that didn't match. + * Any unmatched item having a label will be mentioned explicitly. + * + * @param type - a joi schema object to validate each array item against. + */ + items(...types: SchemaLikeWithoutArray[]): this + + /** + * Specifies the exact number of items in the array. + */ + length(limit: number | Reference): this + + /** + * Specifies the maximum number of items in the array. + */ + max(limit: number | Reference): this + + /** + * Specifies the minimum number of items in the array. + */ + min(limit: number | Reference): this + + /** + * Lists the types in sequence order for the array values where: + * @param type - a joi schema object to validate against each array item in sequence order. type can be multiple values passed as individual arguments. + * If a given type is .required() then there must be a matching item with the same index position in the array. + * Errors will contain the number of items that didn't match. + * Any unmatched item having a label will be mentioned explicitly. + */ + ordered(...types: SchemaLikeWithoutArray[]): this + + /** + * Allow single values to be checked against rules as if it were provided as an array. + * enabled can be used with a falsy value to go back to the default behavior. + */ + single(enabled?: any): this + + /** + * Sorts the array by given order. + */ + sort(options?: ArraySortOptions): this + + /** + * Allow this array to be sparse. + * enabled can be used with a falsy value to go back to the default behavior. + */ + sparse(enabled?: any): this + + /** + * Requires the array values to be unique. + * Remember that if you provide a custom comparator function, + * different types can be passed as parameter depending on the rules you set on items. + * Be aware that a deep equality is performed on elements of the array having a type of object, + * a performance penalty is to be expected for this kind of operation. + */ + unique( + comparator?: string | ComparatorFunction, + options?: ArrayUniqueOptions + ): this +} + +interface ObjectPatternOptions { + fallthrough?: boolean + matches: SchemaLike | Reference +} + +export interface ObjectSchema extends AnySchema { + /** + * Defines an all-or-nothing relationship between keys where if one of the peers is present, all of them are required as well. + * + * Optional settings must be the last argument. + */ + and(...peers: Array): this + + /** + * Appends the allowed object keys. If schema is null, undefined, or {}, no changes will be applied. + */ + append(schema?: SchemaMap): this + + /** + * Verifies an assertion where. + */ + assert(ref: string | Reference, schema: SchemaLike, message?: string): this + + /** + * Requires the object to be an instance of a given constructor. + * + * @param constructor - the constructor function that the object must be an instance of. + * @param name - an alternate name to use in validation errors. This is useful when the constructor function does not have a name. + */ + // tslint:disable-next-line:ban-types + instance(constructor: Function, name?: string): this + + /** + * Sets or extends the allowed object keys. + */ + keys(schema?: SchemaMap): this + + /** + * Specifies the exact number of keys in the object. + */ + length(limit: number): this + + /** + * Specifies the maximum number of keys in the object. + */ + max(limit: number | Reference): this + + /** + * Specifies the minimum number of keys in the object. + */ + min(limit: number | Reference): this + + /** + * Defines a relationship between keys where not all peers can be present at the same time. + * + * Optional settings must be the last argument. + */ + nand(...peers: Array): this + + /** + * Defines a relationship between keys where one of the peers is required (and more than one is allowed). + * + * Optional settings must be the last argument. + */ + or(...peers: Array): this + + /** + * Defines an exclusive relationship between a set of keys where only one is allowed but none are required. + * + * Optional settings must be the last argument. + */ + oxor(...peers: Array): this + + /** + * Specify validation rules for unknown keys matching a pattern. + * + * @param pattern - a pattern that can be either a regular expression or a joi schema that will be tested against the unknown key names + * @param schema - the schema object matching keys must validate against + */ + pattern( + pattern: RegExp | SchemaLike, + schema: SchemaLike, + options?: ObjectPatternOptions + ): this + + /** + * Requires the object to be a Joi reference. + */ + ref(): this + + /** + * Requires the object to be a `RegExp` object. + */ + regex(): this + + /** + * Renames a key to another name (deletes the renamed key). + */ + rename(from: string | RegExp, to: string, options?: RenameOptions): this + + /** + * Requires the object to be a Joi schema instance. + */ + schema(type?: SchemaLike): this + + /** + * Overrides the handling of unknown keys for the scope of the current object only (does not apply to children). + */ + unknown(allow?: boolean): this + + /** + * Requires the presence of other keys whenever the specified key is present. + */ + with( + key: string, + peers: string | string[], + options?: HierarchySeparatorOptions + ): this + + /** + * Forbids the presence of other keys whenever the specified is present. + */ + without( + key: string, + peers: string | string[], + options?: HierarchySeparatorOptions + ): this + + /** + * Defines an exclusive relationship between a set of keys. one of them is required but not at the same time. + * + * Optional settings must be the last argument. + */ + xor(...peers: Array): this +} + +interface BinarySchema extends AnySchema { + /** + * Sets the string encoding format if a string input is converted to a buffer. + */ + encoding(encoding: string): this + + /** + * Specifies the minimum length of the buffer. + */ + min(limit: number | Reference): this + + /** + * Specifies the maximum length of the buffer. + */ + max(limit: number | Reference): this + + /** + * Specifies the exact length of the buffer: + */ + length(limit: number | Reference): this +} + +interface DateSchema extends AnySchema { + /** + * Specifies that the value must be greater than date. + * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, + * allowing to explicitly ensure a date is either in the past or in the future. + * It can also be a reference to another field. + */ + greater(date: "now" | Date | number | string | Reference): this + + /** + * Requires the string value to be in valid ISO 8601 date format. + */ + iso(): this + + /** + * Specifies that the value must be less than date. + * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, + * allowing to explicitly ensure a date is either in the past or in the future. + * It can also be a reference to another field. + */ + less(date: "now" | Date | number | string | Reference): this + + /** + * Specifies the oldest date allowed. + * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, + * allowing to explicitly ensure a date is either in the past or in the future. + * It can also be a reference to another field. + */ + min(date: "now" | Date | number | string | Reference): this + + /** + * Specifies the latest date allowed. + * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, + * allowing to explicitly ensure a date is either in the past or in the future. + * It can also be a reference to another field. + */ + max(date: "now" | Date | number | string | Reference): this + + /** + * Requires the value to be a timestamp interval from Unix Time. + * @param type - the type of timestamp (allowed values are unix or javascript [default]) + */ + timestamp(type?: "javascript" | "unix"): this +} + +interface FunctionSchema extends ObjectSchema { + /** + * Specifies the arity of the function where: + * @param n - the arity expected. + */ + arity(n: number): this + + /** + * Requires the function to be a class. + */ + class(): this + + /** + * Specifies the minimal arity of the function where: + * @param n - the minimal arity expected. + */ + minArity(n: number): this + + /** + * Specifies the minimal arity of the function where: + * @param n - the minimal arity expected. + */ + maxArity(n: number): this +} + +interface AlternativesSchema extends AnySchema { + /** + * Adds a conditional alternative schema type, either based on another key value, or a schema peeking into the current value. + */ + conditional(ref: string | Reference, options: WhenOptions): this + conditional(ref: Schema, options: WhenSchemaOptions): this + + /** + * Requires the validated value to match a specific set of the provided alternative.try() schemas. + * Cannot be combined with `alternatives.conditional()`. + */ + match(mode: "any" | "all" | "one"): this + + /** + * Adds an alternative schema type for attempting to match against the validated value. + */ + try(...types: SchemaLikeWithoutArray[]): this +} + +interface LinkSchema extends AnySchema { + /** + * Same as `any.concat()` but the schema is merged after the link is resolved which allows merging with schemas of the same type as the resolved link. + * Will throw an exception during validation if the merged types are not compatible. + */ + concat(schema: Schema): this + + /** + * Initializes the schema after constructions for cases where the schema has to be constructed first and then initialized. + * If `ref` was not passed to the constructor, `link.ref()` must be called prior to usaged. + */ + ref(ref: string): this +} + +interface Reference extends Exclude { + depth: number + type: string + key: string + root: string + path: string[] + display: string + toString(): string +} + +type ExtensionBoundSchema = Schema & SchemaInternals + +interface RuleArgs { + name: string + ref?: boolean + assert?: ((value: any) => boolean) | AnySchema + message?: string + + /** + * Undocumented properties + */ + normalize?(value: any): any +} + +type RuleMethod = (...args: any[]) => any + +interface ExtensionRule { + /** + * alternative name for this rule. + */ + alias?: string + /** + * whether rule supports multiple invocations. + */ + multi?: boolean + /** + * Dual rule: converts or validates. + */ + convert?: boolean + /** + * list of arguments accepted by `method`. + */ + args?: Array + /** + * rule body. + */ + method?: RuleMethod | false + /** + * validation function. + */ + validate?( + value: any, + helpers: any, + args: Record, + options: any + ): any + + /** + * undocumented flags. + */ + priority?: boolean + manifest?: boolean +} + +interface CoerceResult { + errors?: ErrorReport[] + value?: any +} + +type CoerceFunction = (value: any, helpers: CustomHelpers) => CoerceResult + +interface CoerceObject { + method: CoerceFunction + from?: string | string[] +} + +interface ExtensionFlag { + setter?: string + default?: any +} + +interface ExtensionTermManifest { + mapped: { + from: string + to: string + } +} + +interface ExtensionTerm { + init: any[] | null + register?: any + manifest?: Record +} + +interface Extension { + type: string + args?(...args: SchemaLike[]): Schema + base?: Schema + coerce?: CoerceFunction | CoerceObject + flags?: Record + manifest?: { + build?(obj: ExtensionBoundSchema, desc: Record): any + } + messages?: LanguageMessages | string + modifiers?: Record any> + overrides?: Record Schema> + prepare?(value: any, helpers: CustomHelpers): any + rebuild?(schema: ExtensionBoundSchema): void + rules?: Record> + terms?: Record + validate?(value: any, helpers: CustomHelpers): any + + /** + * undocumented options + */ + cast?: Record< + string, + { from(value: any): any; to(value: any, helpers: CustomHelpers): any } + > + properties?: Record +} + +type ExtensionFactory = (joi: PluginOptionsSchemaJoi) => Extension + +interface Err { + toString(): string +} + +// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + +export interface PluginOptionsSchemaJoi { + /** + * Current version of the joi package. + */ + version: string + + ValidationError: new ( + message: string, + details: any, + original: any + ) => ValidationError + + /** + * Generates a schema object that matches any data type. + */ + any(): AnySchema + + /** + * Generates a schema object that matches an array data type. + */ + array(): ArraySchema + + /** + * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool(). + */ + bool(): BooleanSchema + + /** + * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool(). + */ + boolean(): BooleanSchema + + /** + * Generates a schema object that matches a Buffer data type (as well as the strings which will be converted to Buffers). + */ + binary(): BinarySchema + + /** + * Generates a schema object that matches a date type (as well as a JavaScript date string or number of milliseconds). + */ + date(): DateSchema + + /** + * Generates a schema object that matches a function type. + */ + func(): FunctionSchema + + /** + * Generates a schema object that matches a function type. + */ + function(): FunctionSchema + + /** + * Generates a schema object that matches a number data type (as well as strings that can be converted to numbers). + */ + number(): NumberSchema + + /** + * Generates a schema object that matches an object data type (as well as JSON strings that have been parsed into objects). + */ + // tslint:disable-next-line:no-unnecessary-generics + object( + schema?: SchemaMap + ): ObjectSchema + + /** + * Generates a schema object that matches a string data type. Note that empty strings are not allowed by default and must be enabled with allow(''). + */ + string(): StringSchema + + /** + * Generates a schema object that matches any symbol. + */ + symbol(): SymbolSchema + + /** + * Generates a type that will match one of the provided alternative schemas + */ + alternatives(types: SchemaLike[]): AlternativesSchema + alternatives(...types: SchemaLike[]): AlternativesSchema + + /** + * Alias for `alternatives` + */ + alt(types: SchemaLike[]): AlternativesSchema + alt(...types: SchemaLike[]): AlternativesSchema + + /** + * Links to another schema node and reuses it for validation, typically for creative recursive schemas. + * + * @param ref - the reference to the linked schema node. + * Cannot reference itself or its children as well as other links. + * Links can be expressed in relative terms like value references (`Joi.link('...')`), + * in absolute terms from the schema run-time root (`Joi.link('/a')`), + * or using schema ids implicitly using object keys or explicitly using `any.id()` (`Joi.link('#a.b.c')`). + */ + link(ref?: string): LinkSchema + + /** + * Validates a value against a schema and throws if validation fails. + * + * @param value - the value to validate. + * @param schema - the schema object. + * @param message - optional message string prefix added in front of the error message. may also be an Error object. + */ + assert(value: any, schema: Schema, options?: ValidationOptions): void + assert( + value: any, + schema: Schema, + message: string | Error, + options?: ValidationOptions + ): void + + /** + * Validates a value against a schema, returns valid object, and throws if validation fails. + * + * @param value - the value to validate. + * @param schema - the schema object. + * @param message - optional message string prefix added in front of the error message. may also be an Error object. + */ + attempt(value: any, schema: Schema, options?: ValidationOptions): any + attempt( + value: any, + schema: Schema, + message: string | Error, + options?: ValidationOptions + ): any + + cache: CacheConfiguration + + /** + * Converts literal schema definition to joi schema object (or returns the same back if already a joi schema object). + */ + compile(schema: SchemaLike, options?: CompileOptions): Schema + + /** + * Checks if the provided preferences are valid. + * + * Throws an exception if the prefs object is invalid. + * + * The method is provided to perform inputs validation for the `any.validate()` and `any.validateAsync()` methods. + * Validation is not performed automatically for performance reasons. Instead, manually validate the preferences passed once and reuse. + */ + checkPreferences(prefs: ValidationOptions): void + + /** + * Creates a custom validation schema. + */ + custom(fn: CustomValidator, description?: string): Schema + + /** + * Creates a new Joi instance that will apply defaults onto newly created schemas + * through the use of the fn function that takes exactly one argument, the schema being created. + * + * @param fn - The function must always return a schema, even if untransformed. + */ + defaults(fn: SchemaFunction): PluginOptionsSchemaJoi + + /** + * Generates a dynamic expression using a template string. + */ + expression(template: string, options?: ReferenceOptions): any + + /** + * Creates a new Joi instance customized with the extension(s) you provide included. + */ + extend(...extensions: Array): any + + /** + * Creates a reference that when resolved, is used as an array of values to match against the rule. + */ + in(ref: string, options?: ReferenceOptions): Reference + + /** + * Checks whether or not the provided argument is an instance of ValidationError + */ + isError(error: any): error is ValidationError + + /** + * Checks whether or not the provided argument is an expression. + */ + isExpression(expression: any): boolean + + /** + * Checks whether or not the provided argument is a reference. It's especially useful if you want to post-process error messages. + */ + isRef(ref: any): ref is Reference + + /** + * Checks whether or not the provided argument is a joi schema. + */ + isSchema(schema: any, options?: IsSchemaOptions): boolean + + /** + * A special value used with `any.allow()`, `any.invalid()`, and `any.valid()` as the first value to reset any previously set values. + */ + override: symbol + + /** + * Generates a reference to the value of the named key. + */ + ref(key: string, options?: ReferenceOptions): Reference + + /** + * Returns an object where each key is a plain joi schema type. + * Useful for creating type shortcuts using deconstruction. + * Note that the types are already formed and do not need to be called as functions (e.g. `string`, not `string()`). + */ + types(): { + alternatives: AlternativesSchema + any: AnySchema + array: ArraySchema + binary: BinarySchema + boolean: BooleanSchema + date: DateSchema + function: FunctionSchema + link: LinkSchema + number: NumberSchema + object: ObjectSchema + string: StringSchema + symbol: SymbolSchema + } + + /** + * Generates a dynamic expression using a template string. + */ + x(template: string, options?: ReferenceOptions): any + + // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + // Below are undocumented APIs. use at your own risk + // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + + /** + * Whitelists a value + */ + allow(...values: any[]): Schema + + /** + * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed. + */ + valid(...values: any[]): Schema + equal(...values: any[]): Schema + + /** + * Blacklists a value + */ + invalid(...values: any[]): Schema + disallow(...values: any[]): Schema + not(...values: any[]): Schema + + /** + * Marks a key as required which will not allow undefined as value. All keys are optional by default. + */ + required(): Schema + + /** + * Alias of `required`. + */ + exist(): Schema + + /** + * Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default. + */ + optional(): Schema + + /** + * Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys. + */ + forbidden(): Schema + + /** + * Overrides the global validate() options for the current key and any sub-key. + */ + preferences(options: ValidationOptions): Schema + + /** + * Overrides the global validate() options for the current key and any sub-key. + */ + prefs(options: ValidationOptions): Schema + + /** + * Converts the type into an alternatives type where the conditions are merged into the type definition where: + */ + when(ref: string | Reference, options: WhenOptions): AlternativesSchema + when(ref: Schema, options: WhenSchemaOptions): AlternativesSchema + + /** + * Unsure, maybe alias for `compile`? + */ + build(...args: any[]): any + + /** + * Unsure, maybe alias for `preferences`? + */ + options(...args: any[]): any + + /** + * Unsure, maybe leaked from `@hapi/lab/coverage/initialize` + */ + trace(...args: any[]): any + untrace(...args: any[]): any +} diff --git a/packages/gatsby-plugin-utils/src/validate.ts b/packages/gatsby-plugin-utils/src/validate.ts index 85048793281d2..f5095dd5d3c97 100644 --- a/packages/gatsby-plugin-utils/src/validate.ts +++ b/packages/gatsby-plugin-utils/src/validate.ts @@ -1,4 +1,5 @@ -import { ValidationOptions, ObjectSchema } from "joi" +import { ValidationOptions } from "joi" +import { ObjectSchema } from "./joi" import { IPluginInfoOptions } from "gatsby/dist/bootstrap/load-plugins/types" const validationOptions: ValidationOptions = { From 5dda52f955ac80cc36c0a5daa1aa0f35da0ff14f Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Fri, 16 Oct 2020 11:39:47 +0200 Subject: [PATCH 6/9] Add test for this --- packages/gatsby-plugin-utils/src/validate.ts | 2 +- .../load-plugins/__tests__/load-plugins.ts | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-plugin-utils/src/validate.ts b/packages/gatsby-plugin-utils/src/validate.ts index f5095dd5d3c97..0750a54051307 100644 --- a/packages/gatsby-plugin-utils/src/validate.ts +++ b/packages/gatsby-plugin-utils/src/validate.ts @@ -21,7 +21,7 @@ export async function validateOptionsSchema( ): Promise { const { validateExternalRules } = options - const { value } = await pluginSchema.validateAsync(pluginOptions, { + const value = await pluginSchema.validateAsync(pluginOptions, { ...validationOptions, externals: validateExternalRules, }) diff --git a/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts b/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts index 5b1f088283e7c..ac869f5abf25b 100644 --- a/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts +++ b/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts @@ -290,5 +290,34 @@ describe(`Load plugins`, () => { `) expect(mockProcessExit).toHaveBeenCalledWith(1) }) + + it(`defaults plugin options to the ones defined in the schema`, async () => { + let plugins = await loadPlugins({ + plugins: [ + { + resolve: `gatsby-plugin-google-analytics`, + options: { + trackingId: `fake`, + }, + }, + ], + }) + + plugins = replaceFieldsThatCanVary(plugins) + + expect( + plugins.find(plugin => plugin.name === `gatsby-plugin-google-analytics`) + .pluginOptions + ).toEqual({ + // All the options that have defaults are defined + anonymize: false, + exclude: [], + head: false, + pageTransitionDelay: 0, + plugins: [], + respectDNT: false, + trackingId: `fake`, + }) + }) }) }) From 7120c1f7044e6429992746856161d6fb3be023dd Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Fri, 16 Oct 2020 11:45:15 +0200 Subject: [PATCH 7/9] Update tests that are failing with new functionality --- .../__snapshots__/load-plugins.ts.snap | 9 +++++++++ .../load-plugins/__tests__/load-plugins.ts | 18 +++--------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins/__tests__/__snapshots__/load-plugins.ts.snap b/packages/gatsby/src/bootstrap/load-plugins/__tests__/__snapshots__/load-plugins.ts.snap index 9974efd9676f7..bb418102685e5 100644 --- a/packages/gatsby/src/bootstrap/load-plugins/__tests__/__snapshots__/load-plugins.ts.snap +++ b/packages/gatsby/src/bootstrap/load-plugins/__tests__/__snapshots__/load-plugins.ts.snap @@ -208,6 +208,9 @@ Array [ "onCreateWebpackConfig", ], "pluginOptions": Object { + "allExtensions": false, + "isTSX": true, + "jsxPragma": "React", "plugins": Array [], }, "resolve": "", @@ -485,6 +488,9 @@ Array [ "onCreateWebpackConfig", ], "pluginOptions": Object { + "allExtensions": false, + "isTSX": true, + "jsxPragma": "React", "plugins": Array [], }, "resolve": "", @@ -770,6 +776,9 @@ Array [ "onCreateWebpackConfig", ], "pluginOptions": Object { + "allExtensions": false, + "isTSX": true, + "jsxPragma": "React", "plugins": Array [], }, "resolve": "", diff --git a/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts b/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts index ac869f5abf25b..fb37412cfc3ff 100644 --- a/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts +++ b/packages/gatsby/src/bootstrap/load-plugins/__tests__/load-plugins.ts @@ -120,21 +120,7 @@ describe(`Load plugins`, () => { expect(plugins).toEqual( expect.arrayContaining([ expect.objectContaining({ - browserAPIs: [], - id: ``, name: `gatsby-plugin-typescript`, - nodeAPIs: [ - `pluginOptionsSchema`, - `resolvableExtensions`, - `onCreateBabelConfig`, - `onCreateWebpackConfig`, - ], - pluginOptions: { - plugins: [], - }, - resolve: ``, - ssrAPIs: [], - version: `1.0.0`, }), ]) ) @@ -169,8 +155,10 @@ describe(`Load plugins`, () => { `onCreateWebpackConfig`, ], pluginOptions: { - plugins: [], + allExtensions: false, + isTSX: true, jsxPragma: `h`, + plugins: [], }, resolve: ``, ssrAPIs: [], From 52118ee9a970298a9861922fa0f901f3aa38e661 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Fri, 16 Oct 2020 11:51:27 +0200 Subject: [PATCH 8/9] Add gatsby as a devDep to gatsby-plugin-utils as we need the types --- packages/gatsby-plugin-utils/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-plugin-utils/package.json b/packages/gatsby-plugin-utils/package.json index 41135867b78a3..16a44f8b5b570 100644 --- a/packages/gatsby-plugin-utils/package.json +++ b/packages/gatsby-plugin-utils/package.json @@ -28,6 +28,7 @@ "@babel/core": "^7.11.6", "babel-preset-gatsby-package": "^0.5.3", "cross-env": "^7.0.2", + "gatsby": "^2.24.79", "rimraf": "^3.0.2", "typescript": "^3.9.5" }, From 2499676068a91c778181a382491ea6c1cc55782c Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Fri, 16 Oct 2020 11:58:10 +0200 Subject: [PATCH 9/9] Maybe fix type import --- packages/gatsby-plugin-utils/src/validate.ts | 2 +- packages/gatsby/index.d.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-plugin-utils/src/validate.ts b/packages/gatsby-plugin-utils/src/validate.ts index 0750a54051307..da8666dbaffaf 100644 --- a/packages/gatsby-plugin-utils/src/validate.ts +++ b/packages/gatsby-plugin-utils/src/validate.ts @@ -1,6 +1,6 @@ import { ValidationOptions } from "joi" import { ObjectSchema } from "./joi" -import { IPluginInfoOptions } from "gatsby/dist/bootstrap/load-plugins/types" +import { IPluginInfoOptions } from "gatsby" const validationOptions: ValidationOptions = { // Show all errors at once, rather than only the first one every time diff --git a/packages/gatsby/index.d.ts b/packages/gatsby/index.d.ts index b8a448defead3..12ab67e6c31e2 100644 --- a/packages/gatsby/index.d.ts +++ b/packages/gatsby/index.d.ts @@ -26,6 +26,8 @@ export { withAssetPrefix, } from "gatsby-link" +export { IPluginInfoOptions } from "./src/bootstrap/load-plugins/types" + export const useScrollRestoration: ( key: string ) => {