Skip to content

Commit

Permalink
feat: no-control-regex support v flag (#17405)
Browse files Browse the repository at this point in the history
* feat: `no-control-regex` support v flag

* test: add testcases

* fix: false positives for `uv` flags
  • Loading branch information
ota-meshi committed Jul 26, 2023
1 parent 9254a6c commit d4f02e4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
17 changes: 15 additions & 2 deletions lib/rules/no-control-regex.js
Expand Up @@ -14,6 +14,16 @@ const collector = new (class {
}

onPatternEnter() {

/*
* `RegExpValidator` may parse the pattern twice in one `validatePattern`.
* So `this._controlChars` should be cleared here as well.
*
* For example, the `/(?<a>\x1f)/` regex will parse the pattern twice.
* This is based on the content described in Annex B.
* If the regex contains a `GroupName` and the `u` flag is not used, `ParseText` will be called twice.
* See https://tc39.es/ecma262/2023/multipage/additional-ecmascript-features-for-web-browsers.html#sec-parsepattern-annexb
*/
this._controlChars = [];
}

Expand All @@ -32,10 +42,13 @@ const collector = new (class {

collectControlChars(regexpStr, flags) {
const uFlag = typeof flags === "string" && flags.includes("u");
const vFlag = typeof flags === "string" && flags.includes("v");

this._controlChars = [];
this._source = regexpStr;

try {
this._source = regexpStr;
this._validator.validatePattern(regexpStr, void 0, void 0, uFlag); // Call onCharacter hook
this._validator.validatePattern(regexpStr, void 0, void 0, { unicode: uFlag, unicodeSets: vFlag }); // Call onCharacter hook
} catch {

// Ignore syntax errors in RegExp.
Expand Down
19 changes: 18 additions & 1 deletion tests/lib/rules/no-control-regex.js
Expand Up @@ -33,7 +33,10 @@ ruleTester.run("no-control-regex", rule, {
String.raw`new RegExp("\\u{20}", "u")`,
String.raw`new RegExp("\\u{1F}")`,
String.raw`new RegExp("\\u{1F}", "g")`,
String.raw`new RegExp("\\u{1F}", flags)` // when flags are unknown, this rule assumes there's no `u` flag
String.raw`new RegExp("\\u{1F}", flags)`, // when flags are unknown, this rule assumes there's no `u` flag
String.raw`new RegExp("[\\q{\\u{20}}]", "v")`,
{ code: String.raw`/[\u{20}--B]/v`, parserOptions: { ecmaVersion: 2024 } }

],
invalid: [
{ code: String.raw`var regex = /\x1f/`, errors: [{ messageId: "unexpected", data: { controlChars: "\\x1f" }, type: "Literal" }] },
Expand Down Expand Up @@ -85,6 +88,20 @@ ruleTester.run("no-control-regex", rule, {
{
code: String.raw`new RegExp("\\u{1F}", "gui")`,
errors: [{ messageId: "unexpected", data: { controlChars: "\\x1f" }, type: "Literal" }]
},
{
code: String.raw`new RegExp("[\\q{\\u{1F}}]", "v")`,
errors: [{ messageId: "unexpected", data: { controlChars: "\\x1f" }, type: "Literal" }]
},
{
code: String.raw`/[\u{1F}--B]/v`,
parserOptions: { ecmaVersion: 2024 },
errors: [{ messageId: "unexpected", data: { controlChars: "\\x1f" }, type: "Literal" }]
},
{
code: String.raw`/\x11/; RegExp("foo", "uv");`,
parserOptions: { ecmaVersion: 2024 },
errors: [{ messageId: "unexpected", data: { controlChars: "\\x11" }, type: "Literal", column: 1 }]
}
]
});

0 comments on commit d4f02e4

Please sign in to comment.