Skip to content

Commit 069c6fd

Browse files
committed
[added] withMutation() method
1 parent ad4390c commit 069c6fd

File tree

3 files changed

+65
-14
lines changed

3 files changed

+65
-14
lines changed

src/mixed.js

+26-14
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,20 @@ SchemaType.prototype = {
3838

3939
constructor: SchemaType,
4040

41-
clone(){
41+
clone() {
42+
if (this._mutate)
43+
return this;
44+
4245
return cloneDeep(this);
4346
},
4447

48+
withMutation(fn) {
49+
this._mutate = true
50+
let result = fn(this)
51+
this._mutate = false
52+
return result
53+
},
54+
4555
concat(schema){
4656
if (!schema)
4757
return this
@@ -79,26 +89,28 @@ SchemaType.prototype = {
7989
: this.transforms.reduce(
8090
(value, transform) => transform.call(this, value, _value), _value)
8191

82-
83-
if( value === undefined && _.has(this, '_default') )
92+
if (value === undefined && _.has(this, '_default'))
8493
value = this.default()
8594

8695
return value
8796
},
8897

8998
_resolve(context, parent){
90-
var schema = this;
99+
if (this._deps.length) {
100+
return this._deps.reduce((schema, match) =>
101+
match.resolve(schema, match.getValue(parent, context)), this)
102+
}
91103

92-
return this._deps.reduce((schema, match) =>
93-
match.resolve(schema, match.getValue(parent, context)), schema)
104+
return this
94105
},
95106

96107
//-- tests
97-
_validate(value, options = {}, state = {}) {
108+
_validate(_value, options = {}, state = {}) {
98109
let valids = this._whitelist
99110
, invalids = this._blacklist
100111
, context = options.context
101112
, parent = state.parent
113+
, value = _value
102114
, schema, endEarly, isStrict;
103115

104116
schema = this._resolve(context, parent)
@@ -110,29 +122,29 @@ SchemaType.prototype = {
110122
let errors = [];
111123
let reject = () => Promise.reject(new ValidationError(errors, value));
112124

113-
if ( !state.isCast && !isStrict )
125+
if (!state.isCast && !isStrict)
114126
value = schema._cast(value, options)
115127

116128
// value is cast, we can check if it meets type requirements
117-
if ( value !== undefined && !schema.isType(value) ){
129+
if (value !== undefined && !schema.isType(value)) {
118130
errors.push(schema._typeError({ value, path, type: schema._type }))
119131
if ( endEarly ) return reject()
120132
}
121133

122134
// next check Whitelist for matching values
123-
if ( valids.length && !valids.has(value) ) {
135+
if (valids.length && !valids.has(value)) {
124136
errors.push(schema._whitelistError(valids.values(), path))
125-
if ( endEarly ) return reject()
137+
if (endEarly) return reject()
126138
}
127139

128140
// next check Blacklist for matching values
129-
if ( invalids.has(value) ){
141+
if (invalids.has(value)) {
130142
errors.push(schema._blacklistError(invalids.values(), path))
131-
if ( endEarly ) return reject()
143+
if (endEarly) return reject()
132144
}
133145

134146
// It makes no sense to validate further at this point if their are errors
135-
if ( errors.length )
147+
if (errors.length)
136148
return reject()
137149

138150
let result = schema.tests.map(fn => fn({ value, path, state, schema, options }))

test/mixed.js

+4
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@ describe( 'Mixed Types ', function(){
1616

1717
it('should be immutable', function(){
1818
var inst = mixed(), next;
19+
var sub = inst.sub = mixed()
1920

2021
inst.should.not.equal(next = inst.required())
2122

23+
next.sub.should.equal(sub)
24+
inst.sub.should.equal(next.sub)
25+
2226
inst.should.be.an.instanceOf(mixed)
2327
next.should.be.an.instanceOf(mixed)
2428

test/object.js

+35
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,41 @@ describe('Object types', function(){
107107
})
108108
})
109109

110+
it('should not clone during validating', function(){
111+
var inst = object().shape({
112+
num: number().max(4),
113+
str: string(),
114+
arr: array().of(number().max(6)),
115+
dte: date(),
116+
117+
nested: object()
118+
.shape({ str: string().min(3) })
119+
.required(),
120+
121+
arrNested: array().of(
122+
object().shape({ num: number() })
123+
)
124+
})
125+
126+
let base = mixed.prototype.clone;
127+
let replace = () => mixed.prototype.clone = base
128+
mixed.prototype.clone = function(...args) {
129+
if (!this._mutate)
130+
throw new Error('should not call clone')
131+
132+
return base.apply(this, args)
133+
}
134+
135+
return inst
136+
.validate({
137+
nested: { str: 5 },
138+
arrNested: [{ num: 5 }, { num: '2' }]
139+
})
140+
.then(replace)
141+
.catch(replace)
142+
})
143+
144+
110145
it('should call shape with constructed with an arg', function(){
111146
var inst = object({
112147
prop: mixed()

0 commit comments

Comments
 (0)