Skip to content

Commit cd64f9f

Browse files
committed
Fix sparse() behavior after item conversion
Fixes #909
1 parent c69da1d commit cd64f9f

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

lib/array.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ internals.Array.prototype._base = function (value, state, options) {
7070

7171
if (this._inner.inclusions.length ||
7272
this._inner.exclusions.length ||
73+
this._inner.requireds.length ||
74+
this._inner.ordereds.length ||
7375
!this._flags.sparse) {
7476

7577
// Clone the array so that we don't modify the original
@@ -122,7 +124,7 @@ internals.checkItems = function (items, wasArray, state, options) {
122124
// Sparse
123125

124126
if (!this._flags.sparse && item === undefined) {
125-
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path }, options));
127+
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
126128

127129
if (options.abortEarly) {
128130
return errors;
@@ -163,6 +165,15 @@ internals.checkItems = function (items, wasArray, state, options) {
163165
--i;
164166
--il;
165167
}
168+
else if (!this._flags.sparse && res.value === undefined) {
169+
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
170+
171+
if (options.abortEarly) {
172+
return errors;
173+
}
174+
175+
continue;
176+
}
166177
else {
167178
items[i] = res.value;
168179
}
@@ -196,6 +207,15 @@ internals.checkItems = function (items, wasArray, state, options) {
196207
internals.fastSplice(requireds, j);
197208
--j;
198209
--jl;
210+
211+
if (!this._flags.sparse && res.value === undefined) {
212+
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
213+
214+
if (options.abortEarly) {
215+
return errors;
216+
}
217+
}
218+
199219
break;
200220
}
201221
}
@@ -228,6 +248,10 @@ internals.checkItems = function (items, wasArray, state, options) {
228248
--i;
229249
--il;
230250
}
251+
else if (!this._flags.sparse && res.value === undefined) {
252+
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
253+
errored = true;
254+
}
231255
else {
232256
items[i] = res.value;
233257
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
},
2828
"scripts": {
2929
"test": "lab -t 100 -a code -L",
30+
"test-debug": "node $NODE_DEBUG_OPTION ./node_modules/.bin/lab -a code",
3031
"test-cov-html": "lab -r html -o coverage.html -a code",
3132
"toc": "node generate-readme-toc.js",
3233
"update-npmignore": "npmignore",

test/array.js

+81
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,60 @@ describe('array', () => {
696696
], done);
697697
});
698698

699+
it('errors on undefined value after validation', (done) => {
700+
701+
const schema = Joi.array().items(Joi.object().empty({}));
702+
703+
Helper.validate(schema, [
704+
[[{ a: 1 }, {}, { c: 3 }], false, null, '"value" must not be a sparse array']
705+
], done);
706+
});
707+
708+
it('errors on undefined value after validation with abortEarly false', (done) => {
709+
710+
const schema = Joi.array().items(Joi.object().empty({})).options({ abortEarly: false });
711+
712+
Helper.validate(schema, [
713+
[[{ a: 1 }, {}, 3], false, null, '"value" must not be a sparse array. "value" at position 2 fails because ["2" must be an object]']
714+
], done);
715+
});
716+
717+
it('errors on undefined value after validation with required', (done) => {
718+
719+
const schema = Joi.array().items(Joi.object().empty({}).required());
720+
721+
Helper.validate(schema, [
722+
[[{}, { c: 3 }], false, null, '"value" must not be a sparse array']
723+
], done);
724+
});
725+
726+
it('errors on undefined value after validation with required and abortEarly false', (done) => {
727+
728+
const schema = Joi.array().items(Joi.object().empty({}).required()).options({ abortEarly: false });
729+
730+
Helper.validate(schema, [
731+
[[{}, 3], false, null, '"value" must not be a sparse array. "value" at position 1 fails because ["1" must be an object]']
732+
], done);
733+
});
734+
735+
it('errors on undefined value after validation with ordered', (done) => {
736+
737+
const schema = Joi.array().ordered(Joi.object().empty({}));
738+
739+
Helper.validate(schema, [
740+
[[{}], false, null, '"value" must not be a sparse array']
741+
], done);
742+
});
743+
744+
it('errors on undefined value after validation with ordered and abortEarly false', (done) => {
745+
746+
const schema = Joi.array().ordered(Joi.object().empty({}).required()).options({ abortEarly: false });
747+
748+
Helper.validate(schema, [
749+
[[{}, 3], false, null, '"value" must not be a sparse array. "value" at position 1 fails because array must contain at most 1 items']
750+
], done);
751+
});
752+
699753
it('validates on undefined value with sparse', (done) => {
700754

701755
const schema = Joi.array().items(Joi.number()).sparse();
@@ -706,6 +760,33 @@ describe('array', () => {
706760
], done);
707761
});
708762

763+
it('validates on undefined value after validation', (done) => {
764+
765+
const schema = Joi.array().items(Joi.object().empty({})).sparse();
766+
767+
Helper.validate(schema, [
768+
[[{ a: 1 }, {}, { c: 3 }], true, null, [{ a: 1 }, undefined, { c: 3 }]]
769+
], done);
770+
});
771+
772+
it('validates on undefined value after validation with required', (done) => {
773+
774+
const schema = Joi.array().items(Joi.object().empty({}).required()).sparse();
775+
776+
Helper.validate(schema, [
777+
[[{ a: 1 }, {}, { c: 3 }], true, null, [{ a: 1 }, undefined, { c: 3 }]]
778+
], done);
779+
});
780+
781+
it('validates on undefined value after validation with ordered', (done) => {
782+
783+
const schema = Joi.array().ordered(Joi.object().empty({})).sparse();
784+
785+
Helper.validate(schema, [
786+
[[{}], true, null, [undefined]]
787+
], done);
788+
});
789+
709790
it('switches the sparse flag', (done) => {
710791

711792
const schema = Joi.array().sparse();

0 commit comments

Comments
 (0)