Repository: eslint-community/eslint-plugin-es-x
Pull request #208 (2024-10-31 02:16:56)

Add `es-x/no-regexp-modifiers` rule
related to #201


Patch:
diff --git a/docs/rules/index.md b/docs/rules/index.md
index ab3f0bc..ab101f2 100644
--- a/docs/rules/index.md
+++ b/docs/rules/index.md
@@ -11,6 +11,7 @@ There is a config that enables the rules in this category: [`no-new-in-esnext`]
 | Rule ID | Description |    |
 |:--------|:------------|:--:|
 | [es-x/no-regexp-duplicate-named-capturing-groups](./no-regexp-duplicate-named-capturing-groups.md) | disallow RegExp duplicate named capturing groups. |  |
+| [es-x/no-regexp-modifiers](./no-regexp-modifiers.md) | disallow RegExp Modifiers. |  |
 | [es-x/no-set-prototype-difference](./no-set-prototype-difference.md) | disallow the `Set.prototype.difference` method. |  |
 | [es-x/no-set-prototype-intersection](./no-set-prototype-intersection.md) | disallow the `Set.prototype.intersection` method. |  |
 | [es-x/no-set-prototype-isdisjointfrom](./no-set-prototype-isdisjointfrom.md) | disallow the `Set.prototype.isDisjointFrom` method. |  |
diff --git a/docs/rules/no-regexp-modifiers.md b/docs/rules/no-regexp-modifiers.md
new file mode 100644
index 0000000..b382c20
--- /dev/null
+++ b/docs/rules/no-regexp-modifiers.md
@@ -0,0 +1,33 @@
+---
+title: "es-x/no-regexp-modifiers"
+description: "disallow RegExp Modifiers"
+---
+
+# es-x/no-regexp-modifiers
+> disallow RegExp Modifiers
+
+- ❗ <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
+- ✅ The following configurations enable this rule: [no-new-in-esnext]
+
+This rule reports ES2025 [RegExp Modifiers](https://github.com/tc39/proposal-regexp-modifiers) as errors.
+
+## 💡 Examples
+
+⛔ Examples of **incorrect** code for this rule:
+
+<eslint-playground type="bad">
+
+```js
+/*eslint es-x/no-regexp-modifiers: error */
+const re1 = /^[a-z](?-i:[a-z])$/i;
+const re2 = /^(?i:[a-z])[a-z]$/;
+```
+
+</eslint-playground>
+
+## 📚 References
+
+- [Rule source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/lib/rules/no-regexp-modifiers.js)
+- [Test source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/tests/lib/rules/no-regexp-modifiers.js)
+
+[no-new-in-esnext]: ../configs/index.md#no-new-in-esnext
diff --git a/lib/configs/flat/no-new-in-esnext.js b/lib/configs/flat/no-new-in-esnext.js
index fd08ad6..ad55efc 100644
--- a/lib/configs/flat/no-new-in-esnext.js
+++ b/lib/configs/flat/no-new-in-esnext.js
@@ -12,6 +12,7 @@ module.exports = {
     },
     rules: {
         "es-x/no-regexp-duplicate-named-capturing-groups": "error",
+        "es-x/no-regexp-modifiers": "error",
         "es-x/no-set-prototype-difference": "error",
         "es-x/no-set-prototype-intersection": "error",
         "es-x/no-set-prototype-isdisjointfrom": "error",
diff --git a/lib/configs/no-new-in-esnext.js b/lib/configs/no-new-in-esnext.js
index 9883dc6..ccd73fd 100644
--- a/lib/configs/no-new-in-esnext.js
+++ b/lib/configs/no-new-in-esnext.js
@@ -8,6 +8,7 @@ module.exports = {
     plugins: ["es-x"],
     rules: {
         "es-x/no-regexp-duplicate-named-capturing-groups": "error",
+        "es-x/no-regexp-modifiers": "error",
         "es-x/no-set-prototype-difference": "error",
         "es-x/no-set-prototype-intersection": "error",
         "es-x/no-set-prototype-isdisjointfrom": "error",
diff --git a/lib/index.js b/lib/index.js
index 2ddadcd..9e5aeb3 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -297,6 +297,7 @@ module.exports = {
         "no-regexp-d-flag": require("./rules/no-regexp-d-flag"),
         "no-regexp-duplicate-named-capturing-groups": require("./rules/no-regexp-duplicate-named-capturing-groups"),
         "no-regexp-lookbehind-assertions": require("./rules/no-regexp-lookbehind-assertions"),
+        "no-regexp-modifiers": require("./rules/no-regexp-modifiers"),
         "no-regexp-named-capture-groups": require("./rules/no-regexp-named-capture-groups"),
         "no-regexp-prototype-compile": require("./rules/no-regexp-prototype-compile"),
         "no-regexp-prototype-flags": require("./rules/no-regexp-prototype-flags"),
diff --git a/lib/rules/no-regexp-modifiers.js b/lib/rules/no-regexp-modifiers.js
new file mode 100644
index 0000000..62e3fb7
--- /dev/null
+++ b/lib/rules/no-regexp-modifiers.js
@@ -0,0 +1,58 @@
+"use strict"
+
+const { getSourceCode } = require("eslint-compat-utils")
+const { defineRegExpHandler } = require("../util/define-regexp-handler")
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "disallow RegExp Modifiers.",
+            category: "ES2025",
+            recommended: false,
+            url: "http://eslint-community.github.io/eslint-plugin-es-x/rules/no-regexp-modifiers.html",
+        },
+        fixable: null,
+        messages: {
+            forbidden: "ES2025 RegExp Modifiers are forbidden.",
+        },
+        schema: [],
+        type: "problem",
+    },
+    create(context) {
+        return defineRegExpHandler(context, (node) => {
+            const found = []
+            return {
+                onPatternEnter() {
+                    found.length = 0
+                },
+                onModifiersLeave(start, end) {
+                    found.push({ start, end })
+                },
+                onExit() {
+                    for (const { start, end } of found) {
+                        const sourceCode = getSourceCode(context)
+                        context.report({
+                            node,
+                            loc:
+                                node.type === "Literal"
+                                    ? {
+                                          start: sourceCode.getLocFromIndex(
+                                              node.range[0] +
+                                                  1 /* slash */ +
+                                                  start,
+                                          ),
+                                          end: sourceCode.getLocFromIndex(
+                                              node.range[0] +
+                                                  1 /* slash */ +
+                                                  end,
+                                          ),
+                                      }
+                                    : null,
+                            messageId: "forbidden",
+                        })
+                    }
+                },
+            }
+        })
+    },
+}
diff --git a/package.json b/package.json
index 15affce..ef3b149 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
   },
   "dependencies": {
     "@eslint-community/eslint-utils": "^4.1.2",
-    "@eslint-community/regexpp": "^4.11.0",
+    "@eslint-community/regexpp": "^4.12.1",
     "eslint-compat-utils": "^0.5.1"
   },
   "devDependencies": {
@@ -26,7 +26,7 @@
     "eslint-plugin-n": "^17.8.1",
     "eslint-plugin-prettier": "^5.0.0",
     "eslint-plugin-vue": "^9.25.0",
-    "espree": "^10.1.0",
+    "espree": "^10.3.0",
     "globals": "^15.0.0",
     "jsdom": "^25.0.0",
     "mocha": "^10.0.0",


Test patch:
diff --git a/tests/lib/rules/no-regexp-modifiers.js b/tests/lib/rules/no-regexp-modifiers.js
new file mode 100644
index 0000000..42026d0
--- /dev/null
+++ b/tests/lib/rules/no-regexp-modifiers.js
@@ -0,0 +1,59 @@
+"use strict"
+
+const RuleTester = require("../../tester")
+const rule = require("../../../lib/rules/no-regexp-modifiers.js")
+
+if (!RuleTester.isSupported(2025)) {
+    //eslint-disable-next-line no-console
+    console.log("Skip the tests of no-regexp-modifiers.")
+    return
+}
+
+new RuleTester().run("no-regexp-modifiers", rule, {
+    valid: [
+        String.raw`/(a)/i`,
+        String.raw`/(?:a)/i`,
+        String.raw`/(?<x>a)/`,
+        String.raw`new RegExp("(a)", "i")`,
+        String.raw`new RegExp("(?:a)", "i")`,
+        String.raw`new RegExp("(?<x>a)")`,
+    ],
+    invalid: [
+        {
+            code: String.raw`/(?m:a)/i`,
+            errors: [
+                {
+                    message: "ES2025 RegExp Modifiers are forbidden.",
+                    column: 4,
+                },
+            ],
+        },
+        {
+            code: String.raw`/(?m-i:a)/i`,
+            errors: [
+                {
+                    message: "ES2025 RegExp Modifiers are forbidden.",
+                    column: 4,
+                },
+            ],
+        },
+        {
+            code: String.raw`/(?m-:a)/i`,
+            errors: [
+                {
+                    message: "ES2025 RegExp Modifiers are forbidden.",
+                    column: 4,
+                },
+            ],
+        },
+        {
+            code: String.raw`/(?-i:a)/i`,
+            errors: [
+                {
+                    message: "ES2025 RegExp Modifiers are forbidden.",
+                    column: 4,
+                },
+            ],
+        },
+    ],
+})