Ajv: Allowing regex patterns to specify flags (e.g. case insensitive, global, etc)

Created on 21 Jan 2016  Â·  5Comments  Â·  Source: ajv-validator/ajv

Summary

Using flags in string regexs would be VERY useful in situations where you'd like to reuse a community regex that's slightly tweaked. Passing a string as a regex generally means that you loose the ability to specify Javascript Regex Modfiers that allow you to ignore case and repeat globally. This is particularly useful bc many regexs in the wild are written with them. And bc they don't translate to a string - they cannot be supported or need to be rewritten.

I'm proposing an easy way to allow regex strings to have the flags that we get in Javascript Regex Patterns. Is there interest in this from the community or from you @epoberezkin?

Deeper Motivation / Example

I have a case where I'd like to require that the uri has the schema ("https://" in my case). To do this seems simple enough - just include the regex. Of course the regex for uri is pretty complex. Note that it leverages the 'ignorecase' (i.e. 'i') flag - so you'd need to go through the whole regex to try and make it case sensitive. Error prone, onerous and awesome to maintain.

What I would like to do is just take the 'uri' regex that you've already written and just add the required 'https://' bit to the front of it... keeping the flags intact since I'd obviously like this pattern to be case insensitive.

I wrote a package about a year ago that deals with this problem. It's called 'string-to-regexp' and allows you to write the regex in exactly the same form (though you do need to escape '\' characters).

In principal all you need to do is to replace occurances of new RegExp(str) with strToRegExp(str) -- assuming that you define strToRegExp with a require statement : var strToRegExp = require('string-to-regexp');

It looks to me like we'd only need to put this in 3 places to get the desired effect.

https://github.com/epoberezkin/ajv/blob/master/lib/ajv.js#L307
https://github.com/epoberezkin/ajv/blob/master/lib/compile/formats.js#L127
https://github.com/epoberezkin/ajv/blob/master/lib/compile/index.js#L200

The caveats related to the module are very reasonable. However allowing flags does extend beyond the strings that new RegExp takes - just as the Javascript regex format is slightly different - therefore there is a minute opportunity that this won't work as expected for some strings. BUT that opportunity is very small and we could solve this by allowing an option to turn it on or off in ajv.

Is there any interest in this?

wontfix

All 5 comments

I think the better approach than modifying the behaviour of the standard keyword pattern is to define the custom keyword, e.g. regexp, that would accept the JavaScript regular expression with flags as a string and convert it to RegExp instance:

var rx = str.match(/^\/(.*)\/([gimy]*)$/);
if (rx) var regexp = new RegExp(rx[1], rx[2]);

We also have such function in protojs library.

You may even let it accept an object { pattern: '', flags: '' } so you neither have to worry about escaping '/' characters nor about parsing the string.

I don't really like the option that would change the meaning of the standard JSON-schema keyword for several reasons:

  • changing standard is much worse than extending it
  • regex format will have to be modified as well based on this option
  • it creates a precedent that leads to this amount of variations of how the schema is treated: https://github.com/zaggino/z-schema#features.

I think using custom keyword is better for this situation.

Closing it, please let me know if the proposed solution works for you

Evgeny - I think your proposed solution is just fine - Thank you!

On Jan 21, 2016, at 3:37 AM, Evgeny Poberezkin [email protected] wrote:

I think the better approach than modifying the behaviour of the standard keyword pattern is to define the custom keyword https://github.com/epoberezkin/ajv#defining-custom-keywords, e.g. regexp, that would accept the JavaScript regular expression with flags as a string and convert it to RegExp instance:

var rx = str.match(/^\/(._)\/([gimy]_)$/);
if (rx) var regexp = new RegExp(rx[1], rx[2]);
We also have such function in protojs http://milojs.github.io/proto/proto_string.js.html#toRegExp library.

You may even let it accept an object { pattern: '', flags: '' } so you neither have to worry about escaping '/' characters nor about parsing the string.

I don't really like the option that would change the meaning of the standard JSON-schema keyword. I think using custom keyword is better for such situation.

—
Reply to this email directly or view it on GitHub https://github.com/epoberezkin/ajv/issues/101#issuecomment-173516325.

Sorry to reopen an old issue, but does this not suggest that pattern should allow for flags? https://github.com/json-schema/json-schema/issues/188

Was this page helpful?
0 / 5 - 0 ratings