Skip to content

Commit

Permalink
feat: schemes as conditionals and shortcuts for when()
Browse files Browse the repository at this point in the history
  • Loading branch information
vonagam committed Feb 3, 2019
1 parent a387de8 commit aa19c52
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 5 deletions.
17 changes: 13 additions & 4 deletions src/Condition.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ function callOrConcat(schema) {
return base => base.concat(schema);
}

function makeIsFn(refs, predicate) {
return refs.length < 2 ? predicate : (...values) => values.every(predicate);
}

class Conditional {
constructor(refs, options) {
let { is, then, otherwise } = options;
Expand All @@ -26,10 +30,15 @@ class Conditional {
'either `then:` or `otherwise:` is required for `when()` conditions',
);

let isFn =
typeof is === 'function'
? is
: (...values) => values.every(value => value === is);
let isFn;

if (typeof is === 'function') {
isFn = is;
} else if (isSchema(is)) {
isFn = makeIsFn(this.refs, value => is.isValidSync(value));
} else {
isFn = makeIsFn(this.refs, value => value === is);
}

this.fn = function(...values) {
let currentSchema = values.pop();
Expand Down
8 changes: 8 additions & 0 deletions src/mixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,14 @@ const proto = (SchemaType.prototype = {
},

when(keys, options) {
if (arguments.length === 1) {
options = keys;
keys = '.';
} else if (isSchema(keys) || typeof keys === 'function') {
options = { ...options, is: keys };
keys = '.';
}

var next = this.clone(),
deps = [].concat(keys).map(key => new Ref(key));

Expand Down
64 changes: 63 additions & 1 deletion test/mixed.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { array, mixed, string, number, object, ref, reach, bool } from '../src';
import {
array,
mixed,
string,
number,
object,
ref,
reach,
bool,
ValidationError,
} from '../src';

let noop = () => {};

function ensureSync(fn) {
Expand Down Expand Up @@ -701,6 +712,57 @@ describe('Mixed Types ', () => {
inst.default().should.eql({ prop: undefined });
});

it('should support self references and scheme conditions', async function() {
let inst = mixed()
.strict()
.when('.', {
is: number(),
then: number().min(5),
otherwise: string(),
});

await inst
.validate(4)
.should.be.rejectedWith(ValidationError, /must be greater/);

await inst.validate(5).should.be.fulfilled();

await inst
.validate([])
.should.be.rejectedWith(ValidationError, /must be a `string` type/);

await inst.validate('hello').should.be.fulfilled();
});

it('should support conditional first argument as `is` shortcut', async function() {
let inst = mixed().when(value => typeof value === 'number', {
then: number().min(5),
});

await inst
.validate(4)
.should.be.rejectedWith(ValidationError, /must be greater/);

await inst.validate(5).should.be.fulfilled();

await inst.validate('hello').should.be.fulfilled();
});

it('should support conditional signle argument as options shortcut', async function() {
let inst = mixed().when({
is: value => typeof value === 'number',
then: number().min(5),
});

await inst
.validate(4)
.should.be.rejectedWith(ValidationError, /must be greater/);

await inst.validate(5).should.be.fulfilled();

await inst.validate('hello').should.be.fulfilled();
});

it('should use label in error message', async function() {
let label = 'Label';
let inst = object({
Expand Down

0 comments on commit aa19c52

Please sign in to comment.