Repository: eslint/eslint (js)

Issue:
Add Support for RegExp match indices
<!--
    ESLint adheres to the Open JS Foundation Code of Conduct:
    https://eslint.org/conduct

    This template is for requesting a change that is not a bug fix, rule change, or new rule. If you are here for another reason, please see below:

    1. To report a bug: https://eslint.org/docs/developer-guide/contributing/reporting-bugs
    2. To request a rule change: https://eslint.org/docs/developer-guide/contributing/rule-changes
    3. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    4. If you have any questions, please stop by our chatroom: https://eslint.org/chat

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->



**The version of ESLint you are using.**

7.27.0

**The problem you want to solve.**

Support RegExp match indices officially, as it has reached stage-4.
refs:
https://github.com/tc39/proposals/blob/master/finished-proposals.md
https://github.com/tc39/proposal-regexp-match-indices

**Your take on the correct solution to problem.**

- [x] Ecma262 update: tc39/ecma262#1713
- [x] Acorn update: acornjs/acorn#1039
- [x] `regexpp`update: https://github.com/mysticatea/regexpp/pull/22
- [x] `espree` update: https://github.com/eslint/espree/pull/505
- [ ] `eslint` update: #14653

We probably need to add `d` to the `validFlags ` of the no-invalid-regexp rule.
We probably need to add `d` to the `regex` variable of the no-empty-character-class rule.

**Are you willing to submit a pull request to implement this change?**

I will submit a pull request.


Pull request:
Breaking: support new regex d flag (fixes #14640)
<!--
    Thank you for contributing!

    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

WIP


Remaining steps:

- [x] release `espree`.
- [x] release `regexpp`.
- [x] update `package.json` with the new versions of `espree`.
- [x] update `package.json` with the new versions of `regexpp`.
- [ ] Fix test cases that failed due to upgrading espree.

---

Fixes #14640.

#### Prerequisites checklist

- [x] I have read the [contributing guidelines](https://github.com/eslint/eslint/blob/master/CONTRIBUTING.md).

#### What is the purpose of this pull request? (put an "X" next to an item)

<!--
    The following template is intentionally not a markdown checkbox list for the reasons
    explained in https://github.com/eslint/eslint/pull/12848#issuecomment-580302888
-->

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[x] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain: Upgrade the `espree` and the `regexpp`.

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

#### What changes did you make? (Give an overview)

This PR adds support for ES2022 RegExp Match Indices. Specifically, change the `no-empty-character-class` rule and `no-invalid-regexp` rule to allow the regex `d` flag.
https://github.com/tc39/proposal-regexp-match-indices

#### Is there anything you'd like reviewers to focus on?

I changed the `no-empty-character-class` rule to accept any flags.

Patch:
diff --git a/lib/rules/comma-dangle.js b/lib/rules/comma-dangle.js
index 798c111ec..327dca7f8 100644
--- a/lib/rules/comma-dangle.js
+++ b/lib/rules/comma-dangle.js
@@ -123,7 +123,8 @@ module.exports = {
                         }
                     ]
                 }
-            ]
+            ],
+            additionalItems: false
         },
 
         messages: {
diff --git a/lib/rules/no-empty-character-class.js b/lib/rules/no-empty-character-class.js
index 7dc219fe1..301f03bf3 100644
--- a/lib/rules/no-empty-character-class.js
+++ b/lib/rules/no-empty-character-class.js
@@ -12,16 +12,13 @@
 /*
  * plain-English description of the following regexp:
  * 0. `^` fix the match at the beginning of the string
- * 1. `\/`: the `/` that begins the regexp
- * 2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
- * 2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
- * 2.1. `\\.`: an escape sequence
- * 2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
- * 3. `\/` the `/` that ends the regexp
- * 4. `[gimuy]*`: optional regexp flags
- * 5. `$`: fix the match at the end of the string
+ * 1. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
+ * 1.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
+ * 1.1. `\\.`: an escape sequence
+ * 1.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
+ * 2. `$`: fix the match at the end of the string
  */
-const regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimuys]*$/u;
+const regex = /^([^\\[]|\\.|\[([^\\\]]|\\.)+\])*$/u;
 
 //------------------------------------------------------------------------------
 // Rule Definition
@@ -46,18 +43,12 @@ module.exports = {
     },
 
     create(context) {
-        const sourceCode = context.getSourceCode();
-
         return {
-
-            Literal(node) {
-                const token = sourceCode.getFirstToken(node);
-
-                if (token.type === "RegularExpression" && !regex.test(token.value)) {
+            "Literal[regex]"(node) {
+                if (!regex.test(node.regex.pattern)) {
                     context.report({ node, messageId: "unexpected" });
                 }
             }
-
         };
 
     }
diff --git a/lib/rules/no-invalid-regexp.js b/lib/rules/no-invalid-regexp.js
index 94ad5ba6d..e3c8682e6 100644
--- a/lib/rules/no-invalid-regexp.js
+++ b/lib/rules/no-invalid-regexp.js
@@ -10,7 +10,7 @@
 
 const RegExpValidator = require("regexpp").RegExpValidator;
 const validator = new RegExpValidator();
-const validFlags = /[gimuys]/gu;
+const validFlags = /[dgimsuy]/gu;
 const undefined1 = void 0;
 
 //------------------------------------------------------------------------------
diff --git a/package.json b/package.json
index 1981419c5..593bebf07 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,7 @@
     "natural-compare": "^1.4.0",
     "optionator": "^0.9.1",
     "progress": "^2.0.0",
-    "regexpp": "^3.1.0",
+    "regexpp": "^3.2.0",
     "semver": "^7.2.1",
     "strip-ansi": "^6.0.0",
     "strip-json-comments": "^3.1.0",


Test patch:
diff --git a/tests/lib/rules/no-empty-character-class.js b/tests/lib/rules/no-empty-character-class.js
index 1421c2ad6..fd4cef8ed 100644
--- a/tests/lib/rules/no-empty-character-class.js
+++ b/tests/lib/rules/no-empty-character-class.js
@@ -32,6 +32,7 @@ ruleTester.run("no-empty-character-class", rule, {
         "var foo = /\\s*:\\s*/gim;",
         { code: "var foo = /[\\]]/uy;", parserOptions: { ecmaVersion: 6 } },
         { code: "var foo = /[\\]]/s;", parserOptions: { ecmaVersion: 2018 } },
+        { code: "var foo = /[\\]]/d;", parserOptions: { ecmaVersion: 2022 } },
         "var foo = /\\[]/"
     ],
     invalid: [
@@ -41,6 +42,7 @@ ruleTester.run("no-empty-character-class", rule, {
         { code: "if (/^abc[]/.test(foo)) {}", errors: [{ messageId: "unexpected", type: "Literal" }] },
         { code: "var foo = /[]]/;", errors: [{ messageId: "unexpected", type: "Literal" }] },
         { code: "var foo = /\\[[]/;", errors: [{ messageId: "unexpected", type: "Literal" }] },
-        { code: "var foo = /\\[\\[\\]a-z[]/;", errors: [{ messageId: "unexpected", type: "Literal" }] }
+        { code: "var foo = /\\[\\[\\]a-z[]/;", errors: [{ messageId: "unexpected", type: "Literal" }] },
+        { code: "var foo = /[]]/d;", parserOptions: { ecmaVersion: 2022 }, errors: [{ messageId: "unexpected", type: "Literal" }] }
     ]
 });
diff --git a/tests/lib/rules/no-invalid-regexp.js b/tests/lib/rules/no-invalid-regexp.js
index 6484db816..f1f2b4044 100644
--- a/tests/lib/rules/no-invalid-regexp.js
+++ b/tests/lib/rules/no-invalid-regexp.js
@@ -59,6 +59,9 @@ ruleTester.run("no-invalid-regexp", rule, {
         "new RegExp('(?<𝒜>.)', 'g');",
         "new RegExp('\\\\p{Script=Nandinagari}', 'u');",
 
+        // ES2022
+        "new RegExp('a+(?<Z>z)?', 'd')",
+
         // allowConstructorFlags
         {
             code: "new RegExp('.', 'g')",