Skip to content

Commit

Permalink
Extend multiple types. Closes #2219
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Jan 4, 2020
1 parent bfb77ea commit 03adf22
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 10 deletions.
37 changes: 30 additions & 7 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,19 @@ internals.methods = {

this.assert(extension, Schemas.extension);

Assert(joi[extension.type] === undefined || joi._types.has(extension.type), 'Cannot override name', extension.type);
const expanded = internals.expandExtension(extension, joi);
for (const item of expanded) {
Assert(joi[item.type] === undefined || joi._types.has(item.type), 'Cannot override name', item.type);

const base = extension.base || this.any();
const schema = Extend.type(base, extension);
const base = item.base || this.any();
const schema = Extend.type(base, item);

joi._types.add(extension.type);
joi[extension.type] = function (...args) {
joi._types.add(item.type);
joi[item.type] = function (...args) {

return internals.generate(this, schema, args);
};
return internals.generate(this, schema, args);
};
}
}

return joi;
Expand Down Expand Up @@ -257,4 +260,24 @@ internals.generate = function (root, schema, args) {
};


internals.expandExtension = function (extension, joi) {

if (typeof extension.type === 'string') {
return [extension];
}

const extended = [];
for (const type of joi._types) {
if (extension.type.test(type)) {
const item = Object.assign({}, extension);
item.type = type;
item.base = joi[type]();
extended.push(item);
}
}

return extended;
};


module.exports = internals.root();
10 changes: 7 additions & 3 deletions lib/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ internals.rule = Joi.object({


exports.extension = Joi.object({
type: Joi.string().required(),

type: Joi.alternatives([
Joi.string(),
Joi.object().regex()
])
.required(),
args: Joi.function(),
base: Joi.object().schema(),
base: Joi.object().schema()
.when('type', { is: Joi.object().regex(), then: Joi.forbidden() }),
coerce: [
Joi.function().maxArity(3),
Joi.object({ method: Joi.function().maxArity(3).required(), from: Joi.array().items(Joi.string()).single() })
Expand Down
25 changes: 25 additions & 0 deletions test/extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,31 @@ describe('extension', () => {
expect(special.lowercase().hello().validate('HELLO').error).to.not.exist();
});

it('extends multiple types', () => {

const custom = Joi.extend({
type: /^s/,
rules: {
hello: {
validate(value, helpers, args, options) {

return 'hello';
}
}
}
});

const string = custom.string().hello();
expect(string.type).to.equal('string');
expect(string.hello().validate('goodbye').value).to.equal('hello');

const symbol = custom.symbol().hello();
expect(symbol.type).to.equal('symbol');
expect(symbol.hello().validate(Symbol('x')).value).to.equal('hello');

expect(() => custom.number().hello()).to.throw('custom.number(...).hello is not a function');
});

it('aliases a type', () => {

const custom = Joi.extend({
Expand Down

0 comments on commit 03adf22

Please sign in to comment.