Skip to content

Conversation

@WesTyler
Copy link
Contributor

Per discussions in #1033 and #1020, refactored string().regex(pattern, [name]) to support string().regex(pattern, [name | config]) as follows:

  1. If name is a string it behaves as currently implemented. No change.
  2. If config is an object, it supports the following properties:
  • name: {string}, behaves as currently implemented.
  • invalidate: {boolean}, defaults to false behavior; if true, disallows the provided regex pattern.

Usage:

const schema = Joi.string().regex(/[a-z]/, {
    name      : 'lowercase',
    invalidate: true
});

schema.validate('bad', (err, value) => {
    if (err) {
        // ValidationError: "value" with value "bad" matches the invalidated lowercase pattern
    }
});
schema.validate('BAD', (err, value) => {
    if (err) {} // err === null
});

schema.describe();
/*
{
  type: 'string',
  invalids: [ '' ],
  rules: [ { name: 'invalidatedRegex', arg: /[a-z]/ } ] 
}
*/ 

@WesTyler
Copy link
Contributor Author

(Realized I missed the API doc update. Pushing now)

lib/string.js Outdated

const patternMatch = pattern.test(value);

if ((patternMatch && !patternIsInvalidated) || (!patternMatch && patternIsInvalidated)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clearer with patternMatch ^ patternIsInvalidated.

lib/string.js Outdated
const testName = patternIsInvalidated ? 'invalidatedRegex' : 'regex';

if (pattern.test(value)) {
return this._test(testName, pattern, function (value, state, options) {
Copy link
Collaborator

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.

Copy link
Contributor Author

@WesTyler WesTyler Nov 14, 2016

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
                        }
                    }
                ]
            }

Copy link
Collaborator

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.

Copy link
Contributor Author

@WesTyler WesTyler Nov 14, 2016

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)

lib/string.js Outdated
}

regex(pattern, name) {
regex(pattern, config) {
Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

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 ?

API.md Outdated
- `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.
Copy link
Collaborator

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 ?

API.md Outdated
- `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`.
Copy link
Collaborator

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 :)

lib/string.js Outdated
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'));
Copy link
Collaborator

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 ?

Copy link
Contributor Author

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. :)

@Marsup Marsup added the feature New functionality or improvement label Nov 14, 2016
@Marsup Marsup self-assigned this Nov 14, 2016
Copy link
Collaborator

@Marsup Marsup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're close !

lib/string.js Outdated
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);
Copy link
Collaborator

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;
}

Copy link
Contributor Author

@WesTyler WesTyler Nov 14, 2016

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?

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

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.

lib/string.js Outdated
}

return this.createError((name ? 'string.regex.name' : 'string.regex.base'), { name, pattern, value }, state, options);
const name = typeof patternOptions === 'string' ?
Copy link
Collaborator

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.

lib/string.js Outdated
const name = typeof patternOptions === 'string' ?
patternOptions :
Hoek.reach(patternOptions, 'name');
const baseRegex = patternIsInverted ? 'string.regex.inverted' : 'string.regex.base';
Copy link
Collaborator

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]+$/);

Copy link
Collaborator

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.

API.md Outdated
```
#### `string.regex(pattern, [name])`
#### `string.regex(pattern, [name | config])`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops XD

@Marsup Marsup added this to the 10.0.0 milestone Nov 14, 2016
@Marsup
Copy link
Collaborator

Marsup commented Nov 14, 2016

Enough work for you, I have other ideas but I'll try them out locally, thanks a lot !

@Marsup Marsup merged commit e60376b into hapijs:master Nov 14, 2016
@WesTyler
Copy link
Contributor Author

Awesome, thanks for the feedback and guidance!

Marsup added a commit that referenced this pull request Nov 14, 2016
@Marsup
Copy link
Collaborator

Marsup commented Nov 14, 2016

Just pushed a small fix, just so you know what I was aiming for.

@WesTyler
Copy link
Contributor Author

Ah, I see. Cool 👍

@lock
Copy link

lock bot commented Jan 9, 2020

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.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

feature New functionality or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants