Extending

One of the best parts of @zuze/schema (aside from the cool conditions) is the ability to extend it with your own custom validators/transforms.

Note: There are some special rules about using custom transforms/validators when using the AST API.

Creating Validators#

Validators are simple objects definitions, the only required properties are name and test.

For convenience there's a helper method to help in creating custom tests.

No matter what type of validator async or sync the validator must return a boolean or ValidationError, the latter can be created using the createError method passed in to the validator function.

The signature of a validator test looks like:

test(
value: any,
{
schema: SchemaDefinition,
options: ValidationOptions,
createError: ({message?: string or () => string, params?: object, name?: string }),
resolve: (optionalRef: any) => resolvedValue
}
) : boolean | ValidationError | Promise<boolean | ValidationError>

To return a ValidationError:

const mustBeJim = (value, {createError}) => value === 'jim' || createError();

If optionalRef is not a ref then it will be returned, otherwise the resolved value will be returned:

const myTest = (arg) => (value,{resolve}) => {
console.log(resolve(arg));
};
const context = { a: 'jim' }
validate(mixed(tests(myTest('a'))), 'some value'); // logs 'a';
validate(mixed(tests(myTest(ref('$a')))), 'some value', { context } ); // logs 'jim'

Async#

Async validators are trivial to create - just use async-await.

Note: async validators will not be run (a warning will be logged) in the schema is being validated synchronously.

const mustBeSomethingAsync = async (value,{createError}) => {
try {
await someAsyncCall(value);
return true;
} catch(err) {
return createError({message:err})
}
}

Accepting Arguments#

Most validators require arguments to function correct like:

min(10);
between(10,15);
oneOf(['a','b',ref('fieldA')])

To create a validator that accepts arguments is straightforward:

const containsCharater = character = test(
'containsCharacter',
(value,{createError,resolve}) => value.matches(new RegExp(resolve(character)))
)
const context = { char: 'i' };
mixed(tests(containsCharacter(ref('$char'))), 'jim', { context });

Creating Transforms#

Transform functions are run in the order they have been added to a SchemaDefinition (unless strict is false). @zuze/schema includes a lot of neat transforms by default, but in case you wanted to extend it, it's pretty easy:

const replaceAllAsWith = replaceWith => val => val.replace(/a/gi,replaceWith);
const schema = createSchema(
{
schema: 'string',
transforms: [['replaceAllAsWith','b']]
},
{
transforms: { replaceAllAsWith: () => replaceAllAsWith }
}
);
cast(schema, `Alas, it's too late!`); // 'blbs, it's too lbte!'