diff --git a/src/__tests__/test.test.ts b/src/__tests__/test.test.ts index bd9309e..753a55f 100644 --- a/src/__tests__/test.test.ts +++ b/src/__tests__/test.test.ts @@ -1,3 +1,4 @@ +import * as yup from 'yup'; import { transformAll, transformObject } from '..'; describe('it correctly parses JSON as yup schema', () => { @@ -111,6 +112,39 @@ describe('it correctly parses JSON as yup schema', () => { expect(schema.isValidSync('foo')).toEqual(false); }); + it('handles arrays of schemas as arguments (issue #2)', () => { + function allLessThan(max: number, refs: any[], msg?: string) { + return this.test({ + test(val) { + let value = val; + + refs.forEach((ref) => { + const number = this.resolve(ref); + expect(number).toEqual(expect.any(Number)); + value += number; + }); + + return value < max; + }, + message: msg || `All values must be less than ${max}`, + }); + } + + yup.addMethod(yup.number, 'allLessThan', allLessThan); + + const schema = transformAll([['yup.object', { + foo: [['yup.number'], ['yup.allLessThan', 10, [[['yup.ref', 'baz']], [['yup.ref', 'bar']]]]], + bar: [['yup.number'], ['yup.required']], + baz: [['yup.number'], ['yup.required']], + }]]); + + expect(schema.isValidSync({ + foo: 1, + bar: 1, + baz: 1, + })).toEqual(true); + }); + describe('transformObject', () => { it('transforms an empty object', () => { const obj = transformObject({}); diff --git a/src/index.ts b/src/index.ts index 4b3ef85..d1879e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,29 +32,36 @@ const isYupSchemaDefinition = (value: any): boolean => ( * @param {array} json * @param {object} instance */ -const transformSchema = (json: any[], instance: typeof yup): Schema => ( - json.reduce((schema, value: [string]) => { +const transformSchema = (json: any[], instance: typeof yup): Schema => { + const mapArgument = (argument: any) => { + if (isYupSchemaDefinition(argument)) { + return transformSchema(argument, instance); + } + + // Support nested structures (e.g. an array of schemas like '[ [[...]], [[...]], ...]') + if (Array.isArray(argument)) { + return argument.map(mapArgument); + } + + // Check if the given object is actually a plain object + // This fixes problems with e.g. regex instances + if (Object.prototype.toString.call(argument) === '[object Object]') { + return transformObject(argument, instance); + } + + return argument; + }; + + return json.reduce((schema, value: [string]) => { const [name, ...args] = value; // Grab the real method name const method = name.substr(DEFINITION_PREFIX.length); // Call the method with transformed parameters - return schema[method](...args.map((argument: any) => { - if (isYupSchemaDefinition(argument)) { - return transformSchema(argument, instance); - } - - // Check if the given object is actually a plain object - // This fixes problems with e.g. regex instances - if (Object.prototype.toString.call(argument) === '[object Object]') { - return transformObject(argument, instance); - } - - return argument; - })); - }, instance) -); + return schema[method](...args.map(mapArgument)); + }, instance); +}; /** * Transforms the given object into an object