slimeform
Version:
Form state management and validation for Vue3
383 lines (372 loc) • 14.6 kB
text/typescript
declare global {
interface SymbolConstructor {
readonly observable: symbol;
}
}
type Maybe<T> = T | null | undefined;
type Defined<T> = T extends undefined ? never : T;
type Flags = 's' | 'd' | '';
type ResolveFlags<T, F extends Flags, D = T> = Extract<F, 'd'> extends never ? T : D extends undefined ? T : Defined<T>;
type Params = Record<string, unknown>;
declare class ValidationError extends Error {
value: any;
path?: string;
type?: string;
errors: string[];
params?: Params;
inner: ValidationError[];
static formatError(message: string | ((params: Params) => string) | unknown, params: Params): any;
static isError(err: any): err is ValidationError;
constructor(errorOrErrors: string | ValidationError | readonly ValidationError[], value?: any, field?: string, type?: string, disableStack?: boolean);
[Symbol.toStringTag]: string;
}
type PanicCallback = (err: Error) => void;
type NextCallback = (err: ValidationError[] | ValidationError | null) => void;
type CreateErrorOptions = {
path?: string;
message?: Message<any>;
params?: ExtraParams;
type?: string;
disableStackTrace?: boolean;
};
type TestContext<TContext = {}> = {
path: string;
options: ValidateOptions<TContext>;
originalValue: any;
parent: any;
from?: Array<{
schema: ISchema<any, TContext>;
value: any;
}>;
schema: any;
resolve: <T>(value: T | Reference<T>) => T;
createError: (params?: CreateErrorOptions) => ValidationError;
};
type TestFunction<T = unknown, TContext = {}> = (this: TestContext<TContext>, value: T, context: TestContext<TContext>) => void | boolean | ValidationError | Promise<boolean | ValidationError>;
type TestOptions<TSchema extends AnySchema = AnySchema> = {
value: any;
path?: string;
options: InternalOptions;
originalValue: any;
schema: TSchema;
};
type TestConfig<TValue = unknown, TContext = {}> = {
name?: string;
message?: Message<any>;
test: TestFunction<TValue, TContext>;
params?: ExtraParams;
exclusive?: boolean;
skipAbsent?: boolean;
};
type Test = ((opts: TestOptions, panic: PanicCallback, next: NextCallback) => void) & {
OPTIONS?: TestConfig;
};
declare class ReferenceSet extends Set<unknown | Reference> {
describe(): unknown[];
resolveAll(resolve: (v: unknown | Reference) => unknown): unknown[];
clone(): ReferenceSet;
merge(newItems: ReferenceSet, removeItems: ReferenceSet): ReferenceSet;
}
type SchemaSpec<TDefault> = {
coerce: boolean;
nullable: boolean;
optional: boolean;
default?: TDefault | (() => TDefault);
abortEarly?: boolean;
strip?: boolean;
strict?: boolean;
recursive?: boolean;
disableStackTrace?: boolean;
label?: string | undefined;
meta?: SchemaMetadata;
};
interface CustomSchemaMetadata {
}
type SchemaMetadata = keyof CustomSchemaMetadata extends never ? Record<PropertyKey, any> : CustomSchemaMetadata;
type SchemaOptions<TType, TDefault> = {
type: string;
spec?: Partial<SchemaSpec<TDefault>>;
check: (value: any) => value is NonNullable<TType>;
};
type AnySchema<TType = any, C = any, D = any, F extends Flags = Flags> = Schema<TType, C, D, F>;
interface CastOptions$1<C = {}> {
parent?: any;
context?: C;
assert?: boolean;
stripUnknown?: boolean;
path?: string;
resolved?: boolean;
}
interface CastOptionalityOptions<C = {}> extends Omit<CastOptions$1<C>, 'assert'> {
/**
* Whether or not to throw TypeErrors if casting fails to produce a valid type.
* defaults to `true`. The `'ignore-optionality'` options is provided as a migration
* path from pre-v1 where `schema.nullable().required()` was allowed. When provided
* cast will only throw for values that are the wrong type *not* including `null` and `undefined`
*/
assert: 'ignore-optionality';
}
type RunTest = (opts: TestOptions, panic: PanicCallback, next: NextCallback) => void;
type TestRunOptions = {
tests: RunTest[];
path?: string | undefined;
options: InternalOptions;
originalValue: any;
value: any;
};
interface SchemaRefDescription {
type: 'ref';
key: string;
}
interface SchemaInnerTypeDescription extends SchemaDescription {
innerType?: SchemaFieldDescription | SchemaFieldDescription[];
}
interface SchemaObjectDescription extends SchemaDescription {
fields: Record<string, SchemaFieldDescription>;
}
interface SchemaLazyDescription {
type: string;
label?: string;
meta?: SchemaMetadata;
}
type SchemaFieldDescription = SchemaDescription | SchemaRefDescription | SchemaObjectDescription | SchemaInnerTypeDescription | SchemaLazyDescription;
interface SchemaDescription {
type: string;
label?: string;
meta?: SchemaMetadata;
oneOf: unknown[];
notOneOf: unknown[];
default?: unknown;
nullable: boolean;
optional: boolean;
tests: Array<{
name?: string;
params: ExtraParams | undefined;
}>;
}
declare abstract class Schema<TType = any, TContext = any, TDefault = any, TFlags extends Flags = ''> implements ISchema<TType, TContext, TFlags, TDefault> {
readonly type: string;
readonly __outputType: ResolveFlags<TType, TFlags, TDefault>;
readonly __context: TContext;
readonly __flags: TFlags;
readonly __isYupSchema__: boolean;
readonly __default: TDefault;
readonly deps: readonly string[];
tests: Test[];
transforms: TransformFunction<AnySchema>[];
private conditions;
private _mutate?;
private internalTests;
protected _whitelist: ReferenceSet;
protected _blacklist: ReferenceSet;
protected exclusiveTests: Record<string, boolean>;
protected _typeCheck: (value: any) => value is NonNullable<TType>;
spec: SchemaSpec<any>;
constructor(options: SchemaOptions<TType, any>);
get _type(): string;
clone(spec?: Partial<SchemaSpec<any>>): this;
label(label: string): this;
meta(): SchemaMetadata | undefined;
meta(obj: SchemaMetadata): this;
withMutation<T>(fn: (schema: this) => T): T;
concat(schema: this): this;
concat(schema: AnySchema): AnySchema;
isType(v: unknown): v is TType;
resolve(options: ResolveOptions<TContext>): this;
protected resolveOptions<T extends InternalOptions<any>>(options: T): T;
/**
* Run the configured transform pipeline over an input value.
*/
cast(value: any, options?: CastOptions$1<TContext>): this['__outputType'];
cast(value: any, options: CastOptionalityOptions<TContext>): this['__outputType'] | null | undefined;
protected _cast(rawValue: any, options: CastOptions$1<TContext>): any;
protected _validate(_value: any, options: InternalOptions<TContext> | undefined, panic: (err: Error, value: unknown) => void, next: (err: ValidationError[], value: unknown) => void): void;
/**
* Executes a set of validations, either schema, produced Tests or a nested
* schema validate result.
*/
protected runTests(runOptions: TestRunOptions, panic: (err: Error, value: unknown) => void, next: (errors: ValidationError[], value: unknown) => void): void;
asNestedTest({ key, index, parent, parentPath, originalParent, options, }: NestedTestConfig): RunTest;
validate(value: any, options?: ValidateOptions<TContext>): Promise<this['__outputType']>;
validateSync(value: any, options?: ValidateOptions<TContext>): this['__outputType'];
isValid(value: any, options?: ValidateOptions<TContext>): Promise<boolean>;
isValidSync(value: any, options?: ValidateOptions<TContext>): value is this['__outputType'];
protected _getDefault(options?: ResolveOptions<TContext>): any;
getDefault(options?: ResolveOptions<TContext>): TDefault;
default(def: DefaultThunk<any>): any;
strict(isStrict?: boolean): this;
protected nullability(nullable: boolean, message?: Message<any>): this;
protected optionality(optional: boolean, message?: Message<any>): this;
optional(): any;
defined(message?: Message<any>): any;
nullable(): any;
nonNullable(message?: Message<any>): any;
required(message?: Message<any>): any;
notRequired(): any;
transform(fn: TransformFunction<this>): this;
/**
* Adds a test function to the schema's queue of tests.
* tests can be exclusive or non-exclusive.
*
* - exclusive tests, will replace any existing tests of the same name.
* - non-exclusive: can be stacked
*
* If a non-exclusive test is added to a schema with an exclusive test of the same name
* the exclusive test is removed and further tests of the same name will be stacked.
*
* If an exclusive test is added to a schema with non-exclusive tests of the same name
* the previous tests are removed and further tests of the same name will replace each other.
*/
test(options: TestConfig<this['__outputType'], TContext>): this;
test(test: TestFunction<this['__outputType'], TContext>): this;
test(name: string, test: TestFunction<this['__outputType'], TContext>): this;
test(name: string, message: Message, test: TestFunction<this['__outputType'], TContext>): this;
when(builder: ConditionBuilder<this>): this;
when(keys: string | string[], builder: ConditionBuilder<this>): this;
when(options: ConditionConfig<this>): this;
when(keys: string | string[], options: ConditionConfig<this>): this;
typeError(message: Message): this;
oneOf<U extends TType>(enums: ReadonlyArray<U | Reference>, message?: Message<{
values: any;
}>): this;
oneOf(enums: ReadonlyArray<TType | Reference>, message: Message<{
values: any;
}>): any;
notOneOf<U extends TType>(enums: ReadonlyArray<Maybe<U> | Reference>, message?: Message<{
values: any;
}>): this;
strip(strip?: boolean): any;
/**
* Return a serialized description of the schema including validations, flags, types etc.
*
* @param options Provide any needed context for resolving runtime schema alterations (lazy, when conditions, etc).
*/
describe(options?: ResolveOptions<TContext>): SchemaDescription;
}
interface Schema<TType = any, TContext = any, TDefault = any, TFlags extends Flags = ''> {
validateAt(path: string, value: any, options?: ValidateOptions<TContext>): Promise<any>;
validateSyncAt(path: string, value: any, options?: ValidateOptions<TContext>): any;
equals: Schema['oneOf'];
is: Schema['oneOf'];
not: Schema['notOneOf'];
nope: Schema['notOneOf'];
}
type ReferenceOptions<TValue = unknown> = {
map?: (value: unknown) => TValue;
};
declare class Reference<TValue = unknown> {
readonly key: string;
readonly isContext: boolean;
readonly isValue: boolean;
readonly isSibling: boolean;
readonly path: any;
readonly getter: (data: unknown) => unknown;
readonly map?: (value: unknown) => TValue;
readonly __isYupRef: boolean;
constructor(key: string, options?: ReferenceOptions<TValue>);
getValue(value: any, parent?: {}, context?: {}): TValue;
/**
*
* @param {*} value
* @param {Object} options
* @param {Object=} options.context
* @param {Object=} options.parent
*/
cast(value: any, options?: {
parent?: {};
context?: {};
}): TValue;
resolve(): this;
describe(): SchemaRefDescription;
toString(): string;
static isRef(value: any): value is Reference;
}
type ConditionBuilder<T extends ISchema<any, any>> = (values: any[], schema: T, options: ResolveOptions) => ISchema<any>;
type ConditionConfig<T extends ISchema<any>> = {
is: any | ((...values: any[]) => boolean);
then?: (schema: T) => ISchema<any>;
otherwise?: (schema: T) => ISchema<any>;
};
type ResolveOptions<TContext = any> = {
value?: any;
parent?: any;
context?: TContext;
};
interface ISchema<T, C = any, F extends Flags = any, D = any> {
__flags: F;
__context: C;
__outputType: T;
__default: D;
cast(value: any, options?: CastOptions$1<C>): T;
cast(value: any, options: CastOptionalityOptions<C>): T | null | undefined;
validate(value: any, options?: ValidateOptions<C>): Promise<T>;
asNestedTest(config: NestedTestConfig): Test;
describe(options?: ResolveOptions<C>): SchemaFieldDescription;
resolve(options: ResolveOptions<C>): ISchema<T, C, F>;
}
type DefaultThunk<T, C = any> = T | ((options?: ResolveOptions<C>) => T);
type TransformFunction<T extends AnySchema> = (this: T, value: any, originalValue: any, schema: T) => any;
interface Ancester<TContext> {
schema: ISchema<any, TContext>;
value: any;
}
interface ValidateOptions<TContext = {}> {
/**
* Only validate the input, skipping type casting and transformation. Default - false
*/
strict?: boolean;
/**
* Return from validation methods on the first error rather than after all validations run. Default - true
*/
abortEarly?: boolean;
/**
* Remove unspecified keys from objects. Default - false
*/
stripUnknown?: boolean;
/**
* When false validations will not descend into nested schema (relevant for objects or arrays). Default - true
*/
recursive?: boolean;
/**
* When true ValidationError instance won't include stack trace information. Default - false
*/
disableStackTrace?: boolean;
/**
* Any context needed for validating schema conditions (see: when())
*/
context?: TContext;
}
interface InternalOptions<TContext = any> extends ValidateOptions<TContext> {
__validating?: boolean;
originalValue?: any;
index?: number;
key?: string;
parent?: any;
path?: string;
sync?: boolean;
from?: Ancester<TContext>[];
}
interface MessageParams {
path: string;
value: any;
originalValue: any;
label: string;
type: string;
spec: SchemaSpec<any> & Record<string, unknown>;
}
type Message<Extra extends Record<string, unknown> = any> = string | ((params: Extra & MessageParams) => unknown) | Record<PropertyKey, unknown>;
type ExtraParams = Record<string, unknown>;
interface NestedTestConfig {
options: InternalOptions<any>;
parent: any;
originalParent: any;
parentPath: string | undefined;
key?: string;
index?: number;
}
interface ResolverOptions {
model?: 'validateSync' | 'validate';
}
/** yup field rule resolver */
declare function yupFieldRule<SchemaT extends Schema, TContext = {}>(fieldSchema: SchemaT, schemaOptions?: ValidateOptions<TContext>): (val: unknown) => string | true;
export { type ResolverOptions, yupFieldRule };