-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement String.regex "invalidate" configuration #1035
Conversation
(Realized I missed the API doc update. Pushing now) |
|
||
const patternMatch = pattern.test(value); | ||
|
||
if ((patternMatch && !patternIsInvalidated) || (!patternMatch && patternIsInvalidated)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clearer with patternMatch ^ patternIsInvalidated
.
|
||
if (pattern.test(value)) { | ||
return this._test(testName, pattern, function (value, state, options) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pattern
should now become an object with every details in it (name, pattern, invalidated), I wouldn't change the name of the test depending on the options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the test name to distinguish between a normal regex test and an inverted regex test in the describe
'd value. Using the revision you requested, should the name/pattern/inverted flag just become part of the arg
property on the describe?
{
type: 'string',
invalids: [''],
rules: [
{
name: 'regex',
arg: {
pattern: /[a-z]/,
inverted: true
}
}
]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will automatically if you do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pattern.pattern
gets a bit weird. Especially at this.createError
(end up with a pattern: pattern.pattern
). How about patternObject
with a pattern
property?
(Running low on time on my lunch break. Going to move forward with patternObject
, but willing to change if you disagree)
@@ -91,19 +91,30 @@ internals.String = class extends Any { | |||
}); | |||
} | |||
|
|||
regex(pattern, name) { | |||
regex(pattern, config) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the term options, in readme too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to use "options", but then I have a variable name clash with the test callback defined on line 103.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, didn't see that one. patternOptions
then ?
|
||
Defines a regular expression rule where: | ||
- `pattern` - a regular expression object the string value must match against. | ||
- `name` - optional name for patterns (useful with multiple patterns). Defaults to 'required'. | ||
- `config` - an optional configuration object with the following supported properties: | ||
- `name` - optional pattern name. Defaults to `required`. | ||
- `invalidate` - optional boolean flag. Defaults to `false` behavior. If specified as `true`, the provided pattern will be disallowed instead of required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan of invalidate, it makes me think of caching. What about invert ?
|
||
Defines a regular expression rule where: | ||
- `pattern` - a regular expression object the string value must match against. | ||
- `name` - optional name for patterns (useful with multiple patterns). Defaults to 'required'. | ||
- `config` - an optional configuration object with the following supported properties: | ||
- `name` - optional pattern name. Defaults to `required`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the original, I have absolutely no idea where that Defaults to required
came from, it isn't :)
|
||
Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp'); | ||
|
||
pattern = new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined); // Future version should break this and forbid unsupported regex flags | ||
|
||
return this._test('regex', pattern, function (value, state, options) { | ||
const patternIsInvalidated = (typeof config === 'object' && Hoek.reach(config, 'invalidate')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use hoek to access it since it's a direct property and you just checked it's an object ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Habit. Updating along with other changes. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're close !
pattern: new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined) // Future version should break this and forbid unsupported regex flags | ||
}; | ||
|
||
const patternIsInverted = (typeof patternOptions === 'object' && patternOptions.invert); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (typeof patternOptions === 'string') {
patternOjbect.name = patternOptions;
}
else if (typeof patternOptions === 'object') {
patternOjbect.name = patternOptions.name;
patternObject.invert = !!patternOptions.invert;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For patternObject.name = patternOptions.name;
it looks like I need to have either a conditional check or a fallback value for describe
when name isn't provided:
"name": "[undefined]"
Preference here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are you getting this ? It's not supposed to be stringified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was actually just taking a second look at that. The stringified piece is just because I copied the Lab test output. But I am seeing this:
const schema = Joi.string().regex(/[a-z]/, {
invert: true
});
const description = schema.describe();
console.log(description.rules[0]);
/*
{ name: 'regex',
arg: { pattern: /[a-z]/, name: undefined, invert: true } }
*/
If having name: undefined
is okay, then no problem. I just wouldn't expect any property at all in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a if then, no ternary.
return value; | ||
} | ||
|
||
return this.createError((name ? 'string.regex.name' : 'string.regex.base'), { name, pattern, value }, state, options); | ||
const name = typeof patternOptions === 'string' ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This becomes useless with upper snippet.
const name = typeof patternOptions === 'string' ? | ||
patternOptions : | ||
Hoek.reach(patternOptions, 'name'); | ||
const baseRegex = patternIsInverted ? 'string.regex.inverted' : 'string.regex.base'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error code can be precalculated outside of the test, we should do that.
|
||
```js | ||
const schema = Joi.string().regex(/^[abc]+$/); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing the simpler inlined string.
@@ -1542,14 +1542,26 @@ const schema = Joi.object({ | |||
}); | |||
``` | |||
|
|||
#### `string.regex(pattern, [name])` | |||
#### `string.regex(pattern, [name | config])` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops XD
Enough work for you, I have other ideas but I'll try them out locally, thanks a lot ! |
Awesome, thanks for the feedback and guidance! |
Just pushed a small fix, just so you know what I was aiming for. |
Ah, I see. Cool 👍 |
This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions. |
Per discussions in #1033 and #1020, refactored
string().regex(pattern, [name])
to supportstring().regex(pattern, [name | config])
as follows:name
is a string it behaves as currently implemented. No change.config
is an object, it supports the following properties:name
: {string}, behaves as currently implemented.invalidate
: {boolean}, defaults tofalse
behavior; iftrue
, disallows the provided regex pattern.Usage: