Skip to content

Commit

Permalink
feat: Support nested yup structures as arguments
Browse files Browse the repository at this point in the history
Resolves #2
  • Loading branch information
spaceemotion committed Jul 6, 2020
1 parent 27da1ff commit 8727490
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 17 deletions.
34 changes: 34 additions & 0 deletions src/__tests__/test.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as yup from 'yup';
import { transformAll, transformObject } from '..';

describe('it correctly parses JSON as yup schema', () => {
Expand Down Expand Up @@ -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({});
Expand Down
41 changes: 24 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,36 @@ const isYupSchemaDefinition = (value: any): boolean => (
* @param {array} json
* @param {object} instance
*/
const transformSchema = (json: any[], instance: typeof yup): Schema<any> => (
json.reduce((schema, value: [string]) => {
const transformSchema = (json: any[], instance: typeof yup): Schema<any> => {
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
Expand Down

0 comments on commit 8727490

Please sign in to comment.