From 5bc250f992134c3550b7a45e31b6b82b0acd67b8 Mon Sep 17 00:00:00 2001 From: Jason Quense Date: Tue, 12 Jan 2016 14:11:10 -0500 Subject: [PATCH] [changed] don't clone unspecified object keys --- package.json | 2 ++ src/object.js | 58 ++++++++++++++++++++++--------------------- src/string.js | 22 ++++++++-------- src/util/clone.js | 18 ++++++++------ src/util/condition.js | 3 --- test/string.js | 2 +- 6 files changed, 55 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index eab3286ce..b827dfab7 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "lib/index.js", "scripts": { "test": "npm run build && karma start --single-run", + "tdd": "npm run build && karma start", "clean": "rimaf ./lib/*", "build": "babel src --out-dir lib", "release": "release" @@ -24,6 +25,7 @@ "babel-eslint": "^4.1.4", "babel-loader": "^5.3.2", "babel-plugin-external-helpers": "^1.1.1", + "benchmark": "^2.0.0", "chai": "^1.9.1", "chai-as-promised": "^4.1.1", "eslint": "^0.24.1", diff --git a/src/object.js b/src/object.js index 89fc01703..8636d59c0 100644 --- a/src/object.js +++ b/src/object.js @@ -78,79 +78,81 @@ inherits(ObjectSchema, MixedSchema, { , value = MixedSchema.prototype._cast.call(schema, _value) //should ignore nulls here - if( schema._typeCheck(value) ) { - var fields = schema.fields - , strip = schema._option('stripUnknown', _opts) === true - , extra = Object.keys(value).filter( v => schema._nodes.indexOf(v) === -1) - , props = schema._nodes.concat(extra) + if (!schema._typeCheck(value)) + return value; - return transform(props, function(obj, prop) { + var fields = schema.fields + , strip = schema._option('stripUnknown', _opts) === true + , extra = Object.keys(value).filter( v => schema._nodes.indexOf(v) === -1) + , props = schema._nodes.concat(extra); + + schema.withMutation(() => { + value = transform(props, function(obj, prop) { var exists = has(value, prop); - if( exists && fields[prop] ){ + if (exists && fields[prop]) { var fieldSchema = childSchema(fields[prop], schema.default(undefined)) obj[prop] = fieldSchema.cast(value[prop], { context: obj }) } + else if (exists && !strip) + obj[prop] = value[prop] - else if( exists && !strip) - obj[prop] = cloneDeep(value[prop]) - - else if(fields[prop]){ + else if(fields[prop]) { var fieldDefault = fields[prop].default ? fields[prop].default() : undefined - if ( fieldDefault !== undefined) + if (fieldDefault !== undefined) obj[prop] = fieldDefault } - }, {}) - } + + delete schema._default + }) return value }, _validate(_value, _opts, _state) { var errors = [] - , context, schema, endEarly, recursive; + , state = _state || {} + , context, schema + , endEarly, recursive; - _state = _state || {} - context = _state.parent || (_opts || {}).context + context = state.parent || (_opts || {}).context schema = this._resolve(context) endEarly = schema._option('abortEarly', _opts) recursive = schema._option('recursive', _opts) return MixedSchema.prototype._validate - .call(this, _value, _opts, _state) + .call(this, _value, _opts, state) .catch(endEarly ? null : err => { errors.push(err) return err.value }) .then(value => { - if( !recursive || !isObject(value)) { // only iterate though actual objects + if (!recursive || !isObject(value)) { // only iterate though actual objects if ( errors.length ) throw errors[0] return value } - let result = schema._nodes.map(function(key){ - var path = (_state.path ? (_state.path + '.') : '') + key + let result = schema._nodes.map(function(key) { + var path = (state.path ? (state.path + '.') : '') + key , field = childSchema(schema.fields[key], schema) return field._validate(value[key] , _opts - , { ..._state, key, path, parent: value }) + , { ...state, key, path, parent: value }) }) result = endEarly ? Promise.all(result).catch(scopeError(value)) - : collectErrors(result, value, _state.path, errors) + : collectErrors(result, value, state.path, errors) return result.then(() => value) }) - - }, - concat(schema){ + concat(schema) { var next = MixedSchema.prototype.concat.call(this, schema) next._nodes = sortFields(next.fields, next._excludedEdges) @@ -233,8 +235,8 @@ function unknown(ctx, value) { function sortFields(fields, excludes = []){ var edges = [], nodes = [] - for( var key in fields ) if ( has(fields, key)) { - if ( !~nodes.indexOf(key) ) nodes.push(key) + for (var key in fields) if (has(fields, key)) { + if (!~nodes.indexOf(key)) nodes.push(key) fields[key]._deps && fields[key]._deps.forEach(dep => { //eslint-disable-line no-loop-func diff --git a/src/string.js b/src/string.js index 7a6c45ddd..f122e41dd 100644 --- a/src/string.js +++ b/src/string.js @@ -15,8 +15,8 @@ function StringSchema(){ MixedSchema.call(this, { type: 'string'}) this.transforms.push(function(value) { - if( this.isType(value) ) return value - return value == null ? '' + if (this.isType(value)) return value + return value == null ? '' : value.toString ? value.toString() : '' + value }) } @@ -34,19 +34,19 @@ inherits(StringSchema, MixedSchema, { }, min(min, msg){ - return this.test({ - name: 'min', - exclusive: true, + return this.test({ + name: 'min', + exclusive: true, message: msg || locale.min, params: { min }, - test: value => value == null || value.length >= min + test: value => value == null || value.length >= min }) }, max(max, msg){ - return this.test({ - name: 'max', - exclusive: true, + return this.test({ + name: 'max', + exclusive: true, message: msg || locale.max, params: { max }, test: value => value == null || value.length <= max @@ -54,8 +54,8 @@ inherits(StringSchema, MixedSchema, { }, matches(regex, msg){ - return this.test({ - message: msg || locale.matches, + return this.test({ + message: msg || locale.matches, params: { regex }, test: value => value == null || regex.test(value) }) diff --git a/src/util/clone.js b/src/util/clone.js index e4f5a53c2..1e7aadcbe 100644 --- a/src/util/clone.js +++ b/src/util/clone.js @@ -2,20 +2,25 @@ // Copyright (c) 2011, Yahoo Inc. // All rights reserved. https://github.com/hapijs/hoek/blob/master/LICENSE +var isSchema = schema => schema && !!schema.__isYupSchema__; module.exports = function clone(obj, seen) { var isFirst = !seen + , isImmutable = isSchema(obj) && !isFirst - if (typeof obj !== 'object' || obj === null) + if (typeof obj !== 'object' || obj === null || isImmutable) return obj; - + + // if (global.REPORT_CLONE && isFirst) + // throw new Error() //console.log('clone') + seen = seen || { orig: [], copy: [] }; var lookup = seen.orig.indexOf(obj); if (lookup !== -1) return seen.copy[lookup]; - + var newObj; var cloneDeep = false; @@ -29,8 +34,7 @@ module.exports = function clone(obj, seen) { else { var proto = Object.getPrototypeOf(obj); - - if (proto !== null && (!proto || (proto.__isYupSchema__ && !isFirst)) ) { + if (proto !== null && !proto) { newObj = obj; } else { @@ -52,7 +56,7 @@ module.exports = function clone(obj, seen) { for (var i = 0, il = keys.length; i < il; ++i) { var key = keys[i]; - + var descriptor = Object.getOwnPropertyDescriptor(obj, key); if (descriptor.get || descriptor.set) { @@ -65,4 +69,4 @@ module.exports = function clone(obj, seen) { } return newObj; -} \ No newline at end of file +} diff --git a/src/util/condition.js b/src/util/condition.js index fbed00636..15e48e7f1 100644 --- a/src/util/condition.js +++ b/src/util/condition.js @@ -24,9 +24,6 @@ class Conditional { if( !options.then && !options.otherwise ) throw new TypeError('either `then:` or `otherwise:` is required for `when()` conditions') - // if( options.then && options.then._type !== type || options.otherwise && options.otherwise._type !== type) - // throw new TypeError(`cannot create polymorphic conditionals, \`then\` and \`otherwise\` must be the same type: ${type}`) - is = typeof is === 'function' ? is : ((is, value) => is === value).bind(null, is) diff --git a/test/string.js b/test/string.js index ad9ee4779..2cdeaa2a7 100644 --- a/test/string.js +++ b/test/string.js @@ -71,7 +71,7 @@ describe('String types', function(){ inst.isValid('hel').should.eventually.equal(false), - inst.validate('').should.be.rejected.then(function(err){ + inst.validate('').should.be.rejected.then(function(err) { err.errors.length.should.equal(1) }) ])