Skip to content

Commit fe35fcc

Browse files
committed
Implement regex "invalidate" configuration
1 parent e657a5a commit fe35fcc

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

lib/language.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ exports.errors = {
122122
token: 'must only contain alpha-numeric and underscore characters',
123123
regex: {
124124
base: 'with value "{{!value}}" fails to match the required pattern: {{pattern}}',
125-
name: 'with value "{{!value}}" fails to match the {{name}} pattern'
125+
invalidated: 'with value "{{!value}}" matches the invalidated pattern: {{pattern}}',
126+
name: 'with value "{{!value}}" fails to match the {{name}} pattern',
127+
invalidatedName: 'with value "{{!value}}" matches the invalidated {{name}} pattern'
126128
},
127129
email: 'must be a valid email',
128130
uri: 'must be a valid uri',

lib/string.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,28 @@ internals.String = class extends Any {
9191
});
9292
}
9393

94-
regex(pattern, name) {
94+
regex(pattern, config) {
9595

9696
Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
9797

9898
pattern = new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined); // Future version should break this and forbid unsupported regex flags
9999

100100
return this._test('regex', pattern, function (value, state, options) {
101101

102-
if (pattern.test(value)) {
102+
const patternMatch = pattern.test(value);
103+
const patternIsInvalidated = (typeof config === 'object' && Hoek.reach(config, 'invalidate'));
104+
105+
if ((patternMatch && !patternIsInvalidated) || (!patternMatch && patternIsInvalidated)) {
103106
return value;
104107
}
105108

106-
return this.createError((name ? 'string.regex.name' : 'string.regex.base'), { name, pattern, value }, state, options);
109+
const name = typeof config === 'string' ?
110+
config :
111+
Hoek.reach(config, 'name');
112+
const baseRegex = patternIsInvalidated ? 'string.regex.invalidated' : 'string.regex.base';
113+
const nameRegex = patternIsInvalidated ? 'string.regex.invalidatedName' : 'string.regex.name';
114+
115+
return this.createError((name ? nameRegex : baseRegex), { name, pattern, value }, state, options);
107116
});
108117
}
109118

test/string.js

+31
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,37 @@ describe('string', () => {
875875
done();
876876
});
877877
});
878+
879+
it('should include a pattern name in options object', (done) => {
880+
881+
const schema = Joi.string().regex(/[a-z]+/, { name: 'letters' }).regex(/[0-9]+/, { name: 'numbers' });
882+
schema.validate('abcd', (err, value) => {
883+
884+
expect(err.message).to.contain('numbers pattern');
885+
done();
886+
});
887+
});
888+
889+
it('should "invalidate" regex pattern if specified in options object', (done) => {
890+
891+
const schema = Joi.string().regex(/[a-z]/, { invalidate: true });
892+
Helper.validate(schema, [
893+
['0123456789', true],
894+
['abcdefg', false, null, '"value" with value "abcdefg" matches the invalidated pattern: /[a-z]/']
895+
], done);
896+
});
897+
898+
it('should include invalidated pattern name if specified', (done) => {
899+
900+
const schema = Joi.string().regex(/[a-z]/, {
901+
name : 'lowercase',
902+
invalidate: true
903+
});
904+
Helper.validate(schema, [
905+
['0123456789', true],
906+
['abcdefg', false, null, '"value" with value "abcdefg" matches the invalidated lowercase pattern']
907+
], done);
908+
});
878909
});
879910

880911
describe('ip()', () => {

0 commit comments

Comments
 (0)