Skip to content

Commit e60b712

Browse files
committed
Refs can now generate default even when found
Fixes #749.
1 parent 2d9431e commit e60b712

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,7 @@ References support the following arguments:
15451545
- `options` - optional settings:
15461546
- `separator` - overrides the default `.` hierarchy separator.
15471547
- `contextPrefix` - overrides the default `$` context prefix signifier.
1548+
- `defaultFor` - optional array defining what should be considered as candidate for default in addition to not finding the reference.
15481549
15491550
Note that references can only be used where explicitly supported such as in `valid()` or `invalid()` rules. If upwards
15501551
(parents) references are needed, use [`object.assert()`](#objectassertref-schema-message).

lib/ref.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,34 @@ exports.create = function (key, options) {
1616

1717
const settings = Hoek.clone(options); // options can be reused and modified
1818

19-
const ref = function (value, validationOptions) {
19+
let ref = function (value, validationOptions) {
2020

2121
return Hoek.reach(ref.isContext ? validationOptions.context : value, ref.key, settings);
2222
};
2323

24+
if (options && options.defaultFor) {
25+
Hoek.assert(Array.isArray(options.defaultFor), 'defaultFor must be an array');
26+
27+
const oldRef = ref;
28+
29+
ref = function (value, validationOptions) {
30+
31+
const result = oldRef(value, validationOptions);
32+
33+
if (result !== settings.default && settings.defaultFor.indexOf(result) !== -1) {
34+
return Hoek.clone(settings.default);
35+
}
36+
37+
return result;
38+
};
39+
}
40+
2441
ref.isContext = (key[0] === ((settings && settings.contextPrefix) || '$'));
2542
ref.key = (ref.isContext ? key.slice(1) : key);
2643
ref.path = ref.key.split((settings && settings.separator) || '.');
2744
ref.depth = ref.path.length;
2845
ref.root = ref.path[0];
46+
ref.settings = settings;
2947
ref.isJoi = true;
3048

3149
ref.toString = function () {

test/ref.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,38 @@ describe('ref', () => {
440440
done();
441441
});
442442

443+
it('uses ref default', (done) => {
444+
445+
const schema = Joi.object({
446+
a: Joi.number().min(Joi.ref('b', { default: 2 })),
447+
b: Joi.any()
448+
});
449+
450+
Helper.validate(schema, [
451+
[{ a: 5 }, true],
452+
[{ b: 5 }, true],
453+
[{ a: 1 }, false, null, 'child "a" fails because ["a" must be larger than or equal to 2]'],
454+
[{ a: 0, b: 1 }, false, null, 'child "a" fails because ["a" must be larger than or equal to 1]']
455+
], done);
456+
});
457+
458+
it('uses ref default with defaultFor', (done) => {
459+
460+
const schema = Joi.object({
461+
a: Joi.number().min(Joi.ref('b', { default: 2, defaultFor: ['', 3] })),
462+
b: Joi.any()
463+
});
464+
465+
Helper.validate(schema, [
466+
[{ a: 5 }, true],
467+
[{ b: 5 }, true],
468+
[{ a: 1 }, false, null, 'child "a" fails because ["a" must be larger than or equal to 2]'],
469+
[{ a: 0, b: 1 }, false, null, 'child "a" fails because ["a" must be larger than or equal to 1]'],
470+
[{ a: 1, b: '' }, false, null, 'child "a" fails because ["a" must be larger than or equal to 2]'],
471+
[{ a: 1, b: 3 }, false, null, 'child "a" fails because ["a" must be larger than or equal to 2]']
472+
], done);
473+
});
474+
443475
describe('create()', () => {
444476

445477
it('throws when key is missing', (done) => {

0 commit comments

Comments
 (0)