@naturalcycles/nodejs-lib
Version:
Standard library for Node.js
666 lines (665 loc) • 29.8 kB
TypeScript
import type { ValidationFunction, ValidationFunctionResult } from '@naturalcycles/js-lib';
import type { Set2 } from '@naturalcycles/js-lib/object';
import type { AnyObject, BaseDBEntity, IANATimezone, Inclusiveness, IsoDate, IsoDateTime, IsoMonth, NumberEnum, StringEnum, StringMap, UnixTimestamp, UnixTimestampMillis } from '@naturalcycles/js-lib/types';
import type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec';
import type { Ajv } from 'ajv';
import { AjvValidationError } from './ajvValidationError.js';
export declare const j: {
/**
* Matches literally any value - equivalent to TypeScript's `any` type.
* Use sparingly, as it bypasses type validation entirely.
*/
any(): JBuilder<any, false>;
string(): JString<string, false>;
number(): JNumber<number, false>;
boolean(): JBoolean<boolean, false>;
object: typeof object & {
dbEntity: typeof objectDbEntity;
infer: typeof objectInfer;
any(): JObject<AnyObject, false>;
stringMap<S extends JSchema<any, any>>(schema: S): JObject<StringMap<SchemaOut<S>>>;
/**
* @experimental Look around, maybe you find a rule that is better for your use-case.
*
* For Record<K, V> type of validations.
* ```ts
* const schema = j.object
* .record(
* j
* .string()
* .regex(/^\d{3,4}$/)
* .branded<B>(),
* j.number().nullable(),
* )
* .isOfType<Record<B, number | null>>()
* ```
*
* When the keys of the Record are values from an Enum, prefer `j.object.withEnumKeys`!
*
* Non-matching keys will be stripped from the object, i.e. they will not cause an error.
*
* Caveat: This rule first validates values of every properties of the object, and only then validates the keys.
* A consequence of that is that the validation will throw when there is an unexpected property with a value not matching the value schema.
*/
record: typeof record;
/**
* For Record<ENUM, V> type of validations.
*
* When the keys of the Record are values from an Enum,
* this helper is more performant and behaves in a more conventional manner than `j.object.record` would.
*
*
*/
withEnumKeys: typeof withEnumKeys;
withRegexKeys: typeof withRegexKeys;
/**
* Validates that the value is an instance of the given class/constructor.
*
* ```ts
* j.object.instanceOf(Date) // typed as Date
* j.object.instanceOf(Date).optional() // typed as Date | undefined
* ```
*/
instanceOf<T>(ctor: new (...args: any[]) => T): JBuilder<T, false>;
};
array<OUT, Opt>(itemSchema: JSchema<OUT, Opt>): JArray<OUT, Opt>;
tuple<const S extends JSchema<any, any>[]>(items: S): JTuple<S>;
set<OUT_1, Opt_1>(itemSchema: JSchema<OUT_1, Opt_1>): JSet2Builder<OUT_1, Opt_1>;
buffer(): JBuilder<Buffer, false>;
enum<const T extends readonly (string | number | boolean | null)[] | StringEnum | NumberEnum>(input: T, opt?: JsonBuilderRuleOpt): JEnum<T extends readonly (infer U)[] ? U : T extends StringEnum ? T[keyof T] : T extends NumberEnum ? T[keyof T] : never>;
/**
* Use only with primitive values, otherwise this function will throw to avoid bugs.
* To validate objects, use `anyOfBy`.
*
* Our Ajv is configured to strip unexpected properties from objects,
* and since Ajv is mutating the input, this means that it cannot
* properly validate the same data over multiple schemas.
*
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
* Use `oneOf` when schemas are mutually exclusive.
*/
oneOf<B extends readonly JSchema<any, boolean>[]>(items: [...B]): JBuilder<BuilderOutUnion<B>, false>;
/**
* Use only with primitive values, otherwise this function will throw to avoid bugs.
* To validate objects, use `anyOfBy` or `anyOfThese`.
*
* Our Ajv is configured to strip unexpected properties from objects,
* and since Ajv is mutating the input, this means that it cannot
* properly validate the same data over multiple schemas.
*
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
* Use `oneOf` when schemas are mutually exclusive.
*/
anyOf<B_1 extends readonly JSchema<any, boolean>[]>(items: [...B_1]): JBuilder<BuilderOutUnion<B_1>, false>;
/**
* Pick validation schema for an object based on the value of a specific property.
*
* ```
* const schemaMap = {
* true: successSchema,
* false: errorSchema
* }
*
* const schema = j.anyOfBy('success', schemaMap)
* ```
*/
anyOfBy<D extends Record<PropertyKey, JSchema<any, any>>>(propertyName: string, schemaDictionary: D): JBuilder<AnyOfByOut<D>, false>;
/**
* Custom version of `anyOf` which - in contrast to the original function - does not mutate the input.
* This comes with a performance penalty, so do not use it where performance matters.
*
* ```
* const schema = j.anyOfThese([successSchema, errorSchema])
* ```
*/
anyOfThese<B_2 extends readonly JSchema<any, boolean>[]>(items: [...B_2]): JBuilder<BuilderOutUnion<B_2>, false>;
and(): {
silentBob: () => never;
};
literal<const V extends string | number | boolean | null>(v: V): JEnum<V, false>;
/**
* Create a JSchema from a plain JsonSchema object.
* Useful when the schema is loaded from a JSON file or generated externally.
*
* Optionally accepts a custom Ajv instance and/or inputName for error messages.
*/
fromSchema<OUT_2>(schema: JsonSchema<OUT_2>, cfg?: {
ajv?: Ajv;
inputName?: string;
}): JSchema<OUT_2, false>;
};
export declare const HIDDEN_AJV_SCHEMA: unique symbol;
export type WithCachedAjvSchema<Base, OUT> = Base & {
[HIDDEN_AJV_SCHEMA]: AjvSchema<OUT>;
};
export declare class JSchema<OUT, Opt> implements StandardSchemaV1<unknown, OUT>, StandardJSONSchemaV1<unknown, OUT> {
protected [HIDDEN_AJV_SCHEMA]: AjvSchema<any> | undefined;
protected schema: JsonSchema;
private _cfg?;
constructor(schema: JsonSchema, cfg?: {
ajv?: Ajv;
inputName?: string;
});
private _builtSchema?;
private _compiledFns?;
private _getBuiltSchema;
private _getCompiled;
getSchema(): JsonSchema;
/**
* @deprecated
* The usage of this function is discouraged as it defeats the purpose of having type-safe validation.
*/
castAs<T>(): JSchema<T, Opt>;
/**
* A helper function that takes a type parameter and compares it with the type inferred from the schema.
*
* When the type inferred from the schema differs from the passed-in type,
* the schema becomes unusable, by turning its type into `never`.
*/
isOfType<ExpectedType>(): ExactMatch<ExpectedType, OUT> extends true ? this : never;
/**
* Produces a "clean schema object" without methods.
* Same as if it would be JSON.stringified.
*/
build(): JsonSchema<OUT>;
clone(): this;
cloneAndUpdateSchema(schema: Partial<JsonSchema>): this;
get ['~standard'](): StandardSchemaV1.Props<unknown, OUT> & StandardJSONSchemaV1.Props<unknown, OUT>;
validate(input: unknown, opt?: AjvValidationOptions): OUT;
isValid(input: unknown, opt?: AjvValidationOptions): boolean;
getValidationResult(input: unknown, opt?: AjvValidationOptions): ValidationFunctionResult<OUT, AjvValidationError>;
getValidationFunction(opt?: AjvValidationOptions): ValidationFunction<OUT, AjvValidationError>;
/**
* Specify a function to be called after the normal validation is finished.
*
* This function will receive the validated, type-safe data, and you can use it
* to do further validations, e.g. conditional validations based on certain property values,
* or to do data modifications either by mutating the input or returning a new value.
*
* If you throw an error from this function, it will show up as an error in the validation.
*/
postValidation<OUT2 = OUT>(fn: PostValidatonFn<OUT, OUT2>): JSchema<OUT2, Opt>;
/**
* @experimental
*/
out: OUT;
opt: Opt;
/** Forces OUT to be invariant (prevents covariant subtype matching in object property constraints). */
protected _invariantOut: (x: OUT) => void;
}
export declare class JBuilder<OUT, Opt> extends JSchema<OUT, Opt> {
protected setErrorMessage(ruleName: string, errorMessage: string | undefined): void;
/**
* @deprecated
* The usage of this function is discouraged as it defeats the purpose of having type-safe validation.
*/
castAs<T>(): JBuilder<T, Opt>;
$schema($schema: string): this;
$schemaDraft7(): this;
$id($id: string): this;
title(title: string): this;
description(description: string): this;
deprecated(deprecated?: boolean): this;
type(type: string): this;
default(v: any): this;
instanceof(of: string): this;
/**
* @param optionalValues List of values that should be considered/converted as `undefined`.
*
* This `optionalValues` feature only works when the current schema is nested in an object or array schema,
* due to how mutability works in Ajv.
*
* Make sure this `optional()` call is at the end of your call chain.
*
* When `null` is included in optionalValues, the return type becomes `JSchema`
* (no further chaining allowed) because the schema is wrapped in an anyOf structure.
*/
optional<T extends readonly (string | number | boolean | null)[] | undefined = undefined>(optionalValues?: T): T extends readonly (string | number | boolean | null)[] ? JSchema<OUT | undefined, true> : JBuilder<OUT | undefined, true>;
nullable(): JBuilder<OUT | null, Opt>;
/**
* Locks the given schema chain and no other modification can be done to it.
*/
final(): JSchema<OUT, Opt>;
/**
*
* @param validator A validator function that returns an error message or undefined.
*
* You may add multiple custom validators and they will be executed in the order you added them.
*/
custom<OUT2 = OUT>(validator: CustomValidatorFn): JBuilder<OUT2, Opt>;
/**
*
* @param converter A converter function that returns a new value.
*
* You may add multiple converters and they will be executed in the order you added them,
* each converter receiving the result from the previous one.
*
* This feature only works when the current schema is nested in an object or array schema,
* due to how mutability works in Ajv.
*/
convert<OUT2>(converter: CustomConverterFn<OUT2>): JBuilder<OUT2, Opt>;
}
export declare class JString<OUT extends string | undefined = string, Opt extends boolean = false> extends JBuilder<OUT, Opt> {
constructor();
regex(pattern: RegExp, opt?: JsonBuilderRuleOpt): this;
pattern(pattern: string, opt?: JsonBuilderRuleOpt): this;
minLength(minLength: number): this;
maxLength(maxLength: number): this;
length(exactLength: number): this;
length(minLength: number, maxLength: number): this;
email(opt?: Partial<JsonSchemaStringEmailOptions>): this;
trim(): this;
toLowerCase(): this;
toUpperCase(): this;
truncate(toLength: number): this;
branded<B extends string>(): JString<B, Opt>;
/**
* Validates that the input is a fully-specified YYYY-MM-DD formatted valid IsoDate value.
*
* All previous expectations in the schema chain are dropped - including `.optional()` -
* because this call effectively starts a new schema chain.
*/
isoDate(): JIsoDate;
isoDateTime(): JString<IsoDateTime, Opt>;
isoMonth(): JBuilder<IsoMonth, false>;
/**
* Validates the string format to be JWT.
* Expects the JWT to be signed!
*/
jwt(): this;
url(): this;
ipv4(): this;
ipv6(): this;
slug(): this;
semVer(): this;
languageTag(): this;
countryCode(): this;
currency(): this;
/**
* Validates that the input is a valid IANATimzone value.
*
* All previous expectations in the schema chain are dropped - including `.optional()` -
* because this call effectively starts a new schema chain as an `enum` validation.
*/
ianaTimezone(): JEnum<IANATimezone, false>;
base64Url(): this;
uuid(): this;
}
export interface JsonSchemaStringEmailOptions {
checkTLD: boolean;
}
export declare class JIsoDate<Opt extends boolean = false> extends JBuilder<IsoDate, Opt> {
constructor();
before(date: string): this;
sameOrBefore(date: string): this;
after(date: string): this;
sameOrAfter(date: string): this;
between(fromDate: string, toDate: string, incl: Inclusiveness): this;
}
export interface JsonSchemaIsoDateOptions {
before?: string;
sameOrBefore?: string;
after?: string;
sameOrAfter?: string;
}
export interface JsonSchemaIsoMonthOptions {
}
export declare class JNumber<OUT extends number | undefined = number, Opt extends boolean = false> extends JBuilder<OUT, Opt> {
constructor();
integer(): this;
branded<B extends number>(): JNumber<B, Opt>;
multipleOf(multipleOf: number): this;
min(minimum: number): this;
exclusiveMin(exclusiveMinimum: number): this;
max(maximum: number): this;
exclusiveMax(exclusiveMaximum: number): this;
lessThan(value: number): this;
lessThanOrEqual(value: number): this;
moreThan(value: number): this;
moreThanOrEqual(value: number): this;
equal(value: number): this;
range(minimum: number, maximum: number, incl: Inclusiveness): this;
int32(): this;
int64(): this;
float(): this;
double(): this;
unixTimestamp(): JNumber<UnixTimestamp, Opt>;
unixTimestamp2000(): JNumber<UnixTimestamp, Opt>;
unixTimestampMillis(): JNumber<UnixTimestampMillis, Opt>;
unixTimestamp2000Millis(): JNumber<UnixTimestampMillis, Opt>;
utcOffset(): this;
utcOffsetHour(): this;
/**
* Specify the precision of the floating point numbers by the number of digits after the ".".
* Excess digits will be cut-off when the current schema is nested in an object or array schema,
* due to how mutability works in Ajv.
*/
precision(numberOfDigits: number): this;
}
export declare class JBoolean<OUT extends boolean | undefined = boolean, Opt extends boolean = false> extends JBuilder<OUT, Opt> {
constructor();
}
export declare class JObject<OUT extends AnyObject, Opt extends boolean = false> extends JBuilder<OUT, Opt> {
constructor(props?: AnyObject, opt?: JObjectOpts);
/**
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
*/
allowAdditionalProperties(): this;
extend<P extends Record<string, JSchema<any, any>>>(props: P): JObject<Expand<Override<OUT, {
[K in keyof P as P[K] extends JSchema<any, infer IsOpt> ? IsOpt extends true ? never : K : never]: P[K] extends JSchema<infer OUT2, any> ? OUT2 : never;
} & {
[K in keyof P as P[K] extends JSchema<any, infer IsOpt> ? IsOpt extends true ? K : never : never]?: P[K] extends JSchema<infer OUT2, any> ? OUT2 : never;
}>>, false>;
/**
* Concatenates another schema to the current schema.
*
* It expects you to use `isOfType<T>()` in the chain,
* otherwise the validation will throw. This is to ensure
* that the schemas you concatenated match the intended final type.
*/
concat<OUT2 extends AnyObject>(other: JObject<OUT2, any>): JObject<OUT & OUT2, false>;
/**
* Extends the current schema with `id`, `created` and `updated` according to NC DB conventions.
*/
dbEntity(): JObject<Expand<Override<OUT, {
id: string;
created: JNumber<UnixTimestamp, false>;
updated: JNumber<UnixTimestamp, false>;
} & {}>>, false>;
minProperties(minProperties: number): this;
maxProperties(maxProperties: number): this;
exclusiveProperties(propNames: readonly (keyof OUT & string)[]): this;
}
interface JObjectOpts {
hasIsOfTypeCheck?: false;
patternProperties?: StringMap<JsonSchema<any>>;
keySchema?: JsonSchema;
}
export declare class JObjectInfer<PROPS extends Record<string, JSchema<any, any>>, Opt extends boolean = false> extends JBuilder<Expand<{
[K in keyof PROPS as PROPS[K] extends JSchema<any, infer IsOpt> ? IsOpt extends true ? never : K : never]: PROPS[K] extends JSchema<infer OUT, any> ? OUT : never;
} & {
[K in keyof PROPS as PROPS[K] extends JSchema<any, infer IsOpt> ? IsOpt extends true ? K : never : never]?: PROPS[K] extends JSchema<infer OUT, any> ? OUT : never;
}>, Opt> {
constructor(props?: PROPS);
/**
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
*/
allowAdditionalProperties(): this;
extend<NEW_PROPS extends Record<string, JSchema<any, any>>>(props: NEW_PROPS): JObjectInfer<{
[K in keyof PROPS | keyof NEW_PROPS]: K extends keyof NEW_PROPS ? NEW_PROPS[K] : K extends keyof PROPS ? PROPS[K] : never;
}, Opt>;
/**
* Extends the current schema with `id`, `created` and `updated` according to NC DB conventions.
*/
dbEntity(): JObjectInfer<{ [K in "created" | "id" | "updated" | keyof PROPS]: K extends "created" | "id" | "updated" ? {
id: JString<string, false>;
created: JNumber<UnixTimestamp, false>;
updated: JNumber<UnixTimestamp, false>;
}[K] : K extends keyof PROPS ? PROPS[K] : never; }, Opt>;
}
export declare class JArray<OUT, Opt> extends JBuilder<OUT[], Opt> {
constructor(itemsSchema: JSchema<OUT, Opt>);
minLength(minItems: number): this;
maxLength(maxItems: number): this;
length(exactLength: number): this;
length(minItems: number, maxItems: number): this;
exactLength(length: number): this;
unique(): this;
}
declare class JSet2Builder<OUT, Opt> extends JBuilder<Set2<OUT>, Opt> {
constructor(itemsSchema: JSchema<OUT, Opt>);
min(minItems: number): this;
max(maxItems: number): this;
}
export declare class JEnum<OUT extends string | number | boolean | null, Opt extends boolean = false> extends JBuilder<OUT, Opt> {
constructor(enumValues: readonly OUT[], baseType: EnumBaseType, opt?: JsonBuilderRuleOpt);
branded<B extends OUT>(): JEnum<B, Opt>;
}
export declare class JTuple<ITEMS extends JSchema<any, any>[]> extends JBuilder<TupleOut<ITEMS>, false> {
constructor(items: ITEMS);
}
declare function object(props: AnyObject): never;
declare function object<OUT extends AnyObject>(props: [keyof OUT] extends [never] ? Record<string, never> : {
[K in keyof Required<OUT>]-?: JSchema<OUT[K], any>;
}): [keyof OUT] extends [never] ? never : JObject<OUT, false>;
declare function objectInfer<P extends Record<string, JSchema<any, any>>>(props: P): JObjectInfer<P, false>;
declare function objectDbEntity(props: AnyObject): never;
declare function objectDbEntity<OUT extends BaseDBEntity, EXTRA_KEYS extends Exclude<keyof OUT, keyof BaseDBEntity> = Exclude<keyof OUT, keyof BaseDBEntity>>(props: {
[K in EXTRA_KEYS]-?: BuilderFor<OUT[K]>;
} & (ExactMatch<OUT['id'], BaseDBEntity['id']> extends true ? {
id?: BuilderFor<BaseDBEntity['id']>;
} : {
id: BuilderFor<OUT['id']>;
}) & (ExactMatch<OUT['created'], BaseDBEntity['created']> extends true ? {
created?: BuilderFor<BaseDBEntity['created']>;
} : {
created: BuilderFor<OUT['created']>;
}) & (ExactMatch<OUT['updated'], BaseDBEntity['updated']> extends true ? {
updated?: BuilderFor<BaseDBEntity['updated']>;
} : {
updated: BuilderFor<OUT['updated']>;
})): JObject<OUT, false>;
declare function record<KS extends JSchema<any, any>, VS extends JSchema<any, any>, Opt extends boolean = SchemaOpt<VS>>(keySchema: KS, valueSchema: VS): SchemaOut<KS> extends string ? JObject<Opt extends true ? Partial<Record<SchemaOut<KS>, SchemaOut<VS>>> : Record<SchemaOut<KS>, SchemaOut<VS>>, false> : never;
declare function withRegexKeys<S extends JSchema<any, any>>(keyRegex: RegExp | string, schema: S): JObject<StringMap<SchemaOut<S>>, false>;
/**
* Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
*/
declare function withEnumKeys<const T extends readonly (string | number)[] | StringEnum | NumberEnum, S extends JSchema<any, any>, K extends string | number = EnumKeyUnion<T>, Opt extends boolean = SchemaOpt<S>>(keys: T, schema: S): JObject<Opt extends true ? {
[P in K]?: SchemaOut<S>;
} : {
[P in K]: SchemaOut<S>;
}, false>;
/**
* On creation - compiles ajv validation function.
* Provides convenient methods, error reporting, etc.
*/
export declare class AjvSchema<OUT> {
schema: JsonSchema<OUT>;
private constructor();
/**
* Shortcut for AjvSchema.create(schema, { lazy: true })
*/
static createLazy<OUT>(schema: SchemaHandledByAjv<OUT>, cfg?: Partial<AjvSchemaCfg>): AjvSchema<OUT>;
/**
* Conveniently allows to pass either JsonSchema or JSchema builder, or existing AjvSchema.
* If it's already an AjvSchema - it'll just return it without any processing.
* If it's a Builder - will call `build` before proceeding.
* Otherwise - will construct AjvSchema instance ready to be used.
*/
static create<OUT>(schema: SchemaHandledByAjv<OUT>, cfg?: Partial<AjvSchemaCfg>): AjvSchema<OUT>;
/**
* Creates a minimal AjvSchema wrapper from a pre-compiled validate function.
* Used internally by JSchema to cache a compatible AjvSchema instance.
*/
static _wrap<OUT>(schema: JsonSchema<OUT>, compiledFn: any): AjvSchema<OUT>;
static isSchemaWithCachedAjvSchema<Base, OUT>(schema: Base): schema is WithCachedAjvSchema<Base, OUT>;
static cacheAjvSchema<Base extends AnyObject, OUT>(schema: Base, ajvSchema: AjvSchema<OUT>): WithCachedAjvSchema<Base, OUT>;
static requireCachedAjvSchema<Base, OUT>(schema: WithCachedAjvSchema<Base, OUT>): AjvSchema<OUT>;
readonly cfg: AjvSchemaCfg;
private _compiledFn;
private _getValidateFn;
/**
* It returns the original object just for convenience.
*/
validate(input: unknown, opt?: AjvValidationOptions): OUT;
isValid(input: unknown, opt?: AjvValidationOptions): boolean;
getValidationResult(input: unknown, opt?: AjvValidationOptions): ValidationFunctionResult<OUT, AjvValidationError>;
getValidationFunction(): ValidationFunction<OUT, AjvValidationError>;
private static requireValidJsonSchema;
}
type EnumBaseType = 'string' | 'number' | 'other';
export interface AjvValidationOptions {
/**
* Custom Ajv instance to use for this validation.
* Overrides the default Ajv or any Ajv set at construction time.
* Compiled functions are cached per Ajv instance.
*/
ajv?: Ajv;
/**
* Defaults to true,
* because that's how AJV works by default,
* and what gives it performance advantage.
* (Because we have found that deep-clone is surprisingly slow,
* nearly as slow as Joi validation).
*
* If set to true - AJV will mutate the input in case it needs to apply transformations
* (strip unknown properties, convert types, etc).
*
* If false - it will deep-clone (using JSON.stringify+parse) the input to prevent its mutation.
* Will return the cloned/mutated object.
* Please note that JSON.stringify+parse has side-effects,
* e.g it will transform Buffer into a weird object.
*/
mutateInput?: boolean;
inputName?: string;
inputId?: string;
/**
* Function that returns "original input".
* What is original input?
* It's an input in its original non-mutated form.
* Why is it needed?
* Because we mutates the Input here. And after its been mutated - we no longer
* can include it "how it was" in an error message. So, for that reason we'll use
* `getOriginalInput()`, if it's provided.
*/
getOriginalInput?: () => unknown;
}
export interface AjvSchemaCfg {
/**
* Pass Ajv instance, otherwise Ajv will be created with
* AjvSchema default (not the same as Ajv defaults) parameters
*/
ajv: Ajv;
inputName?: string;
/**
* If true - schema will be compiled on-demand (lazily).
* Default: false.
*/
lazy?: boolean;
}
export type SchemaHandledByAjv<OUT> = JSchema<OUT, any> | JsonSchema<OUT> | AjvSchema<OUT>;
export interface JsonSchema<OUT = unknown> {
readonly out?: OUT;
$schema?: string;
$id?: string;
title?: string;
description?: string;
deprecated?: boolean;
readOnly?: boolean;
writeOnly?: boolean;
type?: string | string[];
items?: JsonSchema;
prefixItems?: JsonSchema[];
properties?: {
[K in keyof OUT]: JsonSchema<OUT[K]>;
};
patternProperties?: StringMap<JsonSchema<any>>;
required?: string[];
additionalProperties?: boolean;
minProperties?: number;
maxProperties?: number;
default?: OUT;
if?: JsonSchema;
then?: JsonSchema;
else?: JsonSchema;
anyOf?: JsonSchema[];
oneOf?: JsonSchema[];
/**
* This is a temporary "intermediate AST" field that is used inside the parser.
* In the final schema this field will NOT be present.
*/
optionalField?: true;
pattern?: string;
minLength?: number;
maxLength?: number;
format?: string;
contentMediaType?: string;
contentEncoding?: string;
multipleOf?: number;
minimum?: number;
exclusiveMinimum?: number;
maximum?: number;
exclusiveMaximum?: number;
minItems?: number;
maxItems?: number;
uniqueItems?: boolean;
enum?: any;
hasIsOfTypeCheck?: boolean;
email?: JsonSchemaStringEmailOptions;
Set2?: JsonSchema;
Buffer?: true;
IsoDate?: JsonSchemaIsoDateOptions;
IsoDateTime?: true;
IsoMonth?: JsonSchemaIsoMonthOptions;
instanceof?: string | string[];
transform?: {
trim?: true;
toLowerCase?: true;
toUpperCase?: true;
truncate?: number;
};
errorMessages?: StringMap<string>;
optionalValues?: (string | number | boolean | null)[];
keySchema?: JsonSchema;
isUndefined?: true;
minProperties2?: number;
exclusiveProperties?: (readonly string[])[];
anyOfBy?: {
propertyName: string;
schemaDictionary: Record<string, JsonSchema>;
};
anyOfThese?: JsonSchema[];
precision?: number;
customValidations?: CustomValidatorFn[];
customConversions?: CustomConverterFn<any>[];
postValidation?: PostValidatonFn<any, OUT>;
}
export type PostValidatonFn<OUT, OUT2> = (v: OUT) => OUT2;
export type CustomValidatorFn = (v: any) => string | undefined;
export type CustomConverterFn<OUT> = (v: any) => OUT;
type Expand<T> = {
[K in keyof T]: T[K];
};
type StripIndexSignatureDeep<T> = T extends readonly unknown[] ? T : T extends Record<string, any> ? {
[K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: StripIndexSignatureDeep<T[K]>;
} : T;
type RelaxIndexSignature<T> = T extends readonly unknown[] ? T : T extends AnyObject ? {
[K in keyof T]: RelaxIndexSignature<T[K]>;
} : T;
type Override<T, U> = Omit<T, keyof U> & U;
declare const allowExtraKeysSymbol: unique symbol;
type HasAllowExtraKeys<T> = T extends {
readonly [allowExtraKeysSymbol]?: true;
} ? true : false;
type IsAny<T> = 0 extends 1 & T ? true : false;
type IsAssignableRelaxed<A, B> = IsAny<RelaxIndexSignature<A>> extends true ? true : [RelaxIndexSignature<A>] extends [B] ? true : false;
type ExactMatchBase<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => (T extends B ? 1 : 2) ? (<T>() => T extends B ? 1 : 2) extends <T>() => (T extends A ? 1 : 2) ? true : false : false;
type ExactMatch<A, B> = HasAllowExtraKeys<B> extends true ? IsAssignableRelaxed<B, A> : ExactMatchBase<Expand<A>, Expand<B>> extends true ? true : ExactMatchBase<Expand<StripIndexSignatureDeep<A>>, Expand<StripIndexSignatureDeep<B>>> extends true ? true : ExactMatchBase<keyof Expand<A>, keyof Expand<B>> extends true ? [Expand<A>] extends [Expand<B>] ? [Expand<B>] extends [Expand<A>] ? true : false : false : false;
type BuilderOutUnion<B extends readonly JSchema<any, any>[]> = {
[K in keyof B]: B[K] extends JSchema<infer O, any> ? O : never;
}[number];
type AnyOfByOut<D extends Record<PropertyKey, JSchema<any, any>>> = {
[K in keyof D]: D[K] extends JSchema<infer O, any> ? O : never;
}[keyof D];
type BuilderFor<T> = JSchema<T, any>;
export interface JsonBuilderRuleOpt {
/**
* Text of error message to return when the validation fails for the given rule:
*
* `{ msg: "is not a valid Oompa-loompa" } => "Object.property is not a valid Oompa-loompa"`
*/
msg?: string;
/**
* A friendly name for what we are validating, that will be used in error messages:
*
* `{ name: "Oompa-loompa" } => "Object.property is not a valid Oompa-loompa"`
*/
name?: string;
}
type EnumKeyUnion<T> = T extends readonly (infer U)[] ? `${U & (string | number)}` : T extends StringEnum | NumberEnum ? `${T[keyof T] & (string | number)}` : never;
type SchemaOut<S> = S extends JSchema<infer OUT, any> ? OUT : never;
type SchemaOpt<S> = S extends JSchema<any, infer Opt> ? (Opt extends true ? true : false) : false;
type TupleOut<T extends readonly JSchema<any, any>[]> = {
[K in keyof T]: T[K] extends JSchema<infer O, any> ? O : never;
};
export {};