From 217e347d6eb487cdd31c3993d104e0fa12ced332 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Tue, 5 Feb 2019 22:14:37 +0300 Subject: [PATCH] feat: rewrite reference --- src/Condition.js | 8 +--- src/Reference.js | 76 +++++++++++++++++++++--------------- src/mixed.js | 8 +--- src/util/createValidation.js | 4 +- test/mixed.js | 20 ++-------- 5 files changed, 55 insertions(+), 61 deletions(-) diff --git a/src/Condition.js b/src/Condition.js index 514e1f82b..9d03437cf 100644 --- a/src/Condition.js +++ b/src/Condition.js @@ -40,13 +40,9 @@ class Conditional { } } - getValue(value, parent, context) { - let values = this.refs.map(r => r.getValue(value, parent, context)); + resolve(ctx, options) { + let values = this.refs.map(ref => ref.getValue(options)); - return values; - } - - resolve(ctx, values) { let schema = this.fn.apply(ctx, values.concat(ctx)); if (schema !== undefined && !isSchema(schema)) diff --git a/src/Reference.js b/src/Reference.js index 9c95167b8..dd6bf977e 100644 --- a/src/Reference.js +++ b/src/Reference.js @@ -1,54 +1,68 @@ import { getter } from 'property-expr'; -let validateName = d => { - if (typeof d !== 'string') - throw new TypeError("ref's must be strings, got: " + d); +const prefixes = { + context: '$', + value: '.', }; export default class Reference { - static isRef(value) { - return !!(value && (value.__isYupRef || value instanceof Reference)); - } + constructor(key, options = {}) { + if (typeof key !== 'string') + throw new TypeError("ref's must be strings, got: " + key); - toString() { - return `Ref(${this.key})`; + this.key = key.trim(); + + this.isContext = this.key[0] === prefixes.context; + this.isValue = this.key[0] === prefixes.value; + this.isParent = this.key === ''; + this.isSibling = !this.isContext && !this.isValue && !this.isParent; + + let prefix = this.isContext + ? prefixes.context + : this.isValue + ? prefixes.value + : ''; + + this.path = this.key.slice(prefix.length); + this.getter = this.path && getter(this.path, true); + this.map = options.map; } - constructor(key, mapFn, options = {}) { - validateName(key); - let prefix = options.contextPrefix || '$'; + getValue(options) { + let result = this.isContext + ? options.context + : this.isValue + ? options.value + : options.parent; - this.key = key.trim(); - this.prefix = prefix; + if (this.getter && result !== undefined) result = this.getter(result || {}); - this.isContext = this.key.indexOf(prefix) === 0; - this.isParent = this.key === ''; - this.isSelf = this.key === '.'; - this.isSibling = !this.isContext && !this.isParent && !this.isSelf; + if (this.map) result = this.map(result); - if (!this.isSelf) { - this.path = this.isContext - ? this.key.slice(this.prefix.length) - : this.key; - this._get = getter(this.path, true); - } + return result; + } - this.map = mapFn || (value => value); + cast(value, options) { + return this.getValue({ ...options, value }); } + resolve() { return this; } - cast(value, { parent, context }) { - return this.getValue(value, parent, context); + describe() { + return { + type: 'ref', + key: this.key, + }; } - getValue(value, parent, context) { - if (!this.isSelf) { - value = this._get(this.isContext ? context : parent || context || {}); - } + toString() { + return `Ref(${this.key})`; + } - return this.map(value); + static isRef(value) { + return value && value.__isYupRef; } } diff --git a/src/mixed.js b/src/mixed.js index f1ee8d769..3dbe14b36 100644 --- a/src/mixed.js +++ b/src/mixed.js @@ -136,11 +136,10 @@ const proto = (SchemaType.prototype = { return !this._typeCheck || this._typeCheck(v); }, - resolve({ value, parent, context }) { + resolve(options) { if (this._conditions.length) { return this._conditions.reduce( - (schema, match) => - match.resolve(schema, match.getValue(value, parent, context)), + (schema, condition) => condition.resolve(schema, options), this, ); } @@ -385,9 +384,6 @@ const proto = (SchemaType.prototype = { if (arguments.length === 1) { options = keys; keys = '.'; - } else if (isSchema(keys) || typeof keys === 'function') { - options = { ...options, is: keys }; - keys = '.'; } var next = this.clone(), diff --git a/src/util/createValidation.js b/src/util/createValidation.js index cddcfb4b8..b46f592da 100644 --- a/src/util/createValidation.js +++ b/src/util/createValidation.js @@ -69,7 +69,9 @@ export default function createValidation(options) { }) { let parent = options.parent; let resolve = item => - Ref.isRef(item) ? item.getValue(value, parent, options.context) : item; + Ref.isRef(item) + ? item.getValue({ value, parent, context: options.context }) + : item; let createError = createErrorFactory({ message, diff --git a/test/mixed.js b/test/mixed.js index 57c965be2..a53293552 100644 --- a/test/mixed.js +++ b/test/mixed.js @@ -648,7 +648,7 @@ describe('Mixed Types ', () => { it('should handle multiple conditionals', function() { let called = false; - let inst = mixed().when(['prop', 'other'], function(prop, other) { + let inst = mixed().when(['$prop', '$other'], function(prop, other) { other.should.equal(true); prop.should.equal(1); called = true; @@ -657,7 +657,7 @@ describe('Mixed Types ', () => { inst.cast({}, { context: { prop: 1, other: true } }); called.should.equal(true); - inst = mixed().when(['prop', 'other'], { + inst = mixed().when(['$prop', '$other'], { is: 5, then: mixed().required(), }); @@ -727,21 +727,7 @@ describe('Mixed Types ', () => { await inst.validate(-1).should.be.fulfilled(); }); - it('should support conditional first argument as `is` shortcut', async function() { - let inst = number().when(value => value > 0, { - 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(-1).should.be.fulfilled(); - }); - - it('should support conditional signle argument as options shortcut', async function() { + it('should support conditional single argument as options shortcut', async function() { let inst = number().when({ is: value => value > 0, then: number().min(5),