diff --git a/lib/types/array.js b/lib/types/array.js index a18d558f2..e99f94256 100755 --- a/lib/types/array.js +++ b/lib/types/array.js @@ -342,6 +342,10 @@ module.exports = Any.extend({ if (ordereds.length) { internals.fillOrderedErrors(schema, errors, ordereds, value, state, prefs); + + if (!errors.length) { + internals.fillDefault(ordereds, value, state, prefs); + } } return errors.length ? errors : value; @@ -677,6 +681,33 @@ internals.fillOrderedErrors = function (schema, errors, ordereds, value, state, }; +internals.fillDefault = function (ordereds, value, state, prefs) { + + const overrides = []; + let trailingUndefined = true; + + for (let i = ordereds.length - 1; i >= 0; --i) { + const ordered = ordereds[i]; + const ancestors = [value, ...state.ancestors]; + const override = ordered.$_validate(undefined, state.localize(state.path, ancestors, ordered), prefs).value; + + if (trailingUndefined) { + if (override === undefined) { + continue; + } + + trailingUndefined = false; + } + + overrides.unshift(override); + } + + if (overrides.length) { + value.push(...overrides); + } +}; + + internals.fastSplice = function (arr, i) { let pos = i; diff --git a/package.json b/package.json index 214775d2b..baec52119 100755 --- a/package.json +++ b/package.json @@ -22,11 +22,11 @@ "@sideway/pinpoint": "^2.0.0" }, "devDependencies": { - "typescript": "4.0.x", "@hapi/bourne": "2.x.x", "@hapi/code": "8.x.x", + "@hapi/joi-legacy-test": "npm:@hapi/joi@15.x.x", "@hapi/lab": "24.x.x", - "@hapi/joi-legacy-test": "npm:@hapi/joi@15.x.x" + "typescript": "4.0.x" }, "scripts": { "prepublishOnly": "cd browser && npm install && npm run build", diff --git a/test/types/array.js b/test/types/array.js index fb7ff4644..7c7c48eee 100755 --- a/test/types/array.js +++ b/test/types/array.js @@ -576,6 +576,75 @@ describe('array', () => { ]); }); + it('can fill the default values into the value array', () => { + + const schema = Joi.array().ordered(Joi.string().required(), Joi.number().default(0), Joi.number().default(6)).required(); + + Helper.validate(schema, [ + [['a'], true, ['a', 0, 6]] + ]); + }); + + it('ignore trailing undefined', () => { + + const schema = Joi.array().ordered(Joi.string().required(), Joi.string(), Joi.number().default(5), Joi.string(), Joi.string()); + + Helper.validate(schema, [ + [['a'], true, ['a', undefined, 5]] + ]); + }); + + it('generate sparse array', () => { + + const schema = Joi.array().ordered(Joi.string(), Joi.number().default(5), Joi.string(), Joi.string().default('f')); + + Helper.validate(schema, [ + [[], true, [undefined, 5, undefined, 'f']] + ]); + }); + + it('fills defaults correctly when nested items contain references', () => { + + const schema = Joi.object({ + info: Joi.object(), + values: Joi.array().ordered( + Joi.string().required(), + Joi.string().default(Joi.ref('...info.firstname')), + Joi.string(), + Joi.string().default(Joi.ref('...info.lastname')), + Joi.string() + ).required() + }); + + Helper.validate(schema, [ + [{ info: { firstname: 'f', lastname: 'e' }, values: ['h'] }, true, { info: { firstname: 'f', lastname: 'e' }, values: ['h', 'f', undefined, 'e'] }], + [{ info: { firstname: 'f', lastname: 'e' }, values: ['h', 'test'] }, true, { info: { firstname: 'f', lastname: 'e' }, values: ['h', 'test', undefined, 'e'] }] + ]); + }); + + it('fills defaults correctly when nested items contain references', () => { + + const schema = Joi.object({ + info: Joi.object().required(), + values: Joi.array().ordered( + Joi.string().required(), + Joi.array().ordered( + Joi.string(), + Joi.string().default('normal value'), + Joi.string(), + Joi.number().default(Joi.x('{number("202099")}')) + ), + Joi.string(), + Joi.string().default(Joi.ref('...info.firstname')), + Joi.string() + ).required() + }); + + Helper.validate(schema, [ + [{ info: { firstname: 'f' }, values: ['h', []] }, true, { info: { firstname: 'f' }, values: ['h', [undefined, 'normal value', undefined, 202099], undefined, 'f'] }] + ]); + }); + it('can strip matching items', () => { const schema = Joi.array().items(Joi.string(), Joi.any().strip());