Skip to content

Commit

Permalink
[changed] don't clone unspecified object keys
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense committed Jan 12, 2016
1 parent 069c6fd commit 5bc250f
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 50 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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",
Expand Down
58 changes: 30 additions & 28 deletions src/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
22 changes: 11 additions & 11 deletions src/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
}
Expand All @@ -34,28 +34,28 @@ 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
})
},

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)
})
Expand Down
18 changes: 11 additions & 7 deletions src/util/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 {
Expand All @@ -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) {
Expand All @@ -65,4 +69,4 @@ module.exports = function clone(obj, seen) {
}

return newObj;
}
}
3 changes: 0 additions & 3 deletions src/util/condition.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion test/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
])
Expand Down

0 comments on commit 5bc250f

Please sign in to comment.