From 69c0ad40fefd8711e87b00cdf32304671bc71d1c Mon Sep 17 00:00:00 2001 From: Jason Quense Date: Mon, 18 Jul 2016 17:52:46 -0400 Subject: [PATCH] [fixed] array().concat() incorrectly cleared the sub-schema --- src/array.js | 29 ++++++++++++++++++++++++++--- src/util/reach.js | 13 +++++++++---- test/array.js | 16 ++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/array.js b/src/array.js index 7aa0600..0ceb91d 100644 --- a/src/array.js +++ b/src/array.js @@ -1,5 +1,8 @@ +import typeOf from 'type-name'; + import inherits from './util/inherits'; import isAbsent from './util/isAbsent'; +import isSchema from './util/isSchema'; import MixedSchema from './mixed'; import { mixed, array as locale } from './locale.js'; import runValidations, { propagateErrors } from './util/runValidations'; @@ -15,7 +18,9 @@ function ArraySchema(type) { MixedSchema.call(this, { type: 'array'}) - this._subType = null; + // `undefined` specifically means uninitialized, as opposed to + // "no subtype" + this._subType = undefined; this.withMutation(() => { this.transform(function(values) { @@ -91,9 +96,27 @@ inherits(ArraySchema, MixedSchema, { }) }, - of(schema){ + // concat(schema) { + // var next = MixedSchema.prototype.concat.call(this, schema) + // + // next._subType = schema._subType === undefined + // ? this._subType + // : schema._subType; + // + // return next + // }, + + of(schema) { var next = this.clone() - next._subType = schema + + if (schema !== false && !isSchema(schema)) + throw new TypeError( + '`array.of()` sub-schema must be a valid yup schema, or `false` to negate a current sub-schema. ' + + 'got: ' + typeOf(schema) + ' instead' + ) + + next._subType = schema; + return next }, diff --git a/src/util/reach.js b/src/util/reach.js index d56306f..6ad1f99 100644 --- a/src/util/reach.js +++ b/src/util/reach.js @@ -12,18 +12,19 @@ module.exports = function (obj, path, value, context) { forEach(path, (_part, isBracket, isArray) => { let part = isBracket ? trim(_part) : _part; - if (isArray || has(obj, '_subType')) { // we skipped an array - let idx = isArray ? parseInt(part, 10) : 0 + if (isArray || has(obj, '_subType')) { // we skipped an array: foo[].bar + let idx = isArray ? parseInt(part, 10) : 0; + obj = obj.resolve({ context, parent, value })._subType; if (value) { - if (isArray && idx >= value.length) { throw new Error( `Yup.reach cannot resolve an array item at index: ${_part}, in the path: ${path}. ` + `because there is no value at that index. ` ) } + value = value[idx] } } @@ -45,5 +46,9 @@ module.exports = function (obj, path, value, context) { } }) - return obj && obj.resolve({ context, parent, value }) + if (obj) { + obj = obj.resolve({ context, parent, value }); + } + + return obj } diff --git a/test/array.js b/test/array.js index 834dbce..0876d67 100644 --- a/test/array.js +++ b/test/array.js @@ -63,6 +63,22 @@ describe('Array types', function(){ .cast(['1', '3']).should.eql([1, 3]) }) + it('should concat subType correctly', function(){ + expect( + array() + .of(number()) + .concat(array()) + ._subType + ).to.exist + + expect( + array() + .of(number()) + .concat(array().of(false)) + ._subType + ).to.equal(false) + }) + it('should pass options to children', function(){ array( object({ name: string() })