Skip to content

Commit 2566b63

Browse files
committed
Add es-x/no-regexp-duplicate-named-capturing-groups rule
1 parent a0ba53e commit 2566b63

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
title: "es-x/no-regexp-duplicate-named-capturing-groups"
3+
description: "disallow RegExp duplicate named capturing groups"
4+
---
5+
6+
# es-x/no-regexp-duplicate-named-capturing-groups
7+
> disallow RegExp duplicate named capturing groups
8+
9+
- ❗ <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
10+
11+
This rule reports ES2025 [RegExp duplicate named capture groups](https://github.com/tc39/proposal-duplicate-named-capturing-groups) as errors.
12+
13+
## 💡 Examples
14+
15+
⛔ Examples of **incorrect** code for this rule:
16+
17+
<eslint-playground type="bad">
18+
19+
```js
20+
/*eslint es-x/no-regexp-duplicate-named-capturing-groups: error */
21+
const r1 = /(?<year>\d{4})-\d{2}|\d{2}-(?<year>\d{4})/
22+
const r2 = /(?<x>a)|(?<x>b)/
23+
```
24+
25+
</eslint-playground>
26+
27+
## 📚 References
28+
29+
- [Rule source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/lib/rules/no-regexp-duplicate-named-capturing-groups.js)
30+
- [Test source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/tests/lib/rules/no-regexp-duplicate-named-capturing-groups.js)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"use strict"
2+
3+
const { getSourceCode } = require("eslint-compat-utils")
4+
const { defineRegExpHandler } = require("../util/define-regexp-handler")
5+
6+
module.exports = {
7+
meta: {
8+
docs: {
9+
description: "disallow RegExp duplicate named capturing groups.",
10+
category: "ES2025",
11+
recommended: false,
12+
url: "http://eslint-community.github.io/eslint-plugin-es-x/rules/no-regexp-duplicate-named-capturing-groups.html",
13+
},
14+
fixable: null,
15+
messages: {
16+
forbidden:
17+
"ES2025 RegExp duplicate named capturing groups are forbidden.",
18+
},
19+
schema: [],
20+
type: "problem",
21+
},
22+
create(context) {
23+
return defineRegExpHandler(context, (node) => {
24+
const found = new Map()
25+
return {
26+
onPatternEnter() {
27+
found.clear()
28+
},
29+
onCapturingGroupLeave(start, end, name) {
30+
if (!name) {
31+
return
32+
}
33+
const list = found.get(name)
34+
if (list) {
35+
list.push({ start, end })
36+
} else {
37+
found.set(name, [{ start, end }])
38+
}
39+
},
40+
onExit() {
41+
for (const [, dupe] of found.values()) {
42+
if (!dupe) {
43+
continue
44+
}
45+
const { start, end } = dupe
46+
const sourceCode = getSourceCode(context)
47+
context.report({
48+
node,
49+
loc:
50+
node.type === "Literal"
51+
? {
52+
start: sourceCode.getLocFromIndex(
53+
node.range[0] +
54+
1 /* slash */ +
55+
start,
56+
),
57+
end: sourceCode.getLocFromIndex(
58+
node.range[0] +
59+
1 /* slash */ +
60+
end,
61+
),
62+
}
63+
: null,
64+
messageId: "forbidden",
65+
})
66+
}
67+
},
68+
}
69+
})
70+
},
71+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"use strict"
2+
3+
const RuleTester = require("../../tester")
4+
const rule = require("../../../lib/rules/no-regexp-duplicate-named-capturing-groups.js")
5+
6+
if (!RuleTester.isSupported(2025)) {
7+
//eslint-disable-next-line no-console
8+
console.log("Skip the tests of no-regexp-duplicate-named-capturing-groups.")
9+
return
10+
}
11+
12+
new RuleTester().run("no-regexp-duplicate-named-capturing-groups", rule, {
13+
valid: [
14+
String.raw`/(?<x>a)/`,
15+
String.raw`/(a)/`,
16+
String.raw`/(?<x>a)(?<y>b)/`,
17+
String.raw`/(?<x>a)(b)/`,
18+
String.raw`/(?<x>a)|(?<y>b)/`,
19+
String.raw`new RegExp("(?<x>a)")`,
20+
String.raw`new RegExp("(a)")`,
21+
String.raw`new RegExp("(?<x>a)(?<y>b)")`,
22+
String.raw`new RegExp("(?<x>a)(b)")`,
23+
String.raw`new RegExp("(?<x>a)|(?<y>b)")`,
24+
],
25+
invalid: [
26+
{
27+
code: String.raw`/(?<x>a)|(?<x>b)/`,
28+
errors: [
29+
{
30+
message:
31+
"ES2025 RegExp duplicate named capturing groups are forbidden.",
32+
column: 10,
33+
},
34+
],
35+
},
36+
{
37+
code: String.raw`/(?<x>a)|(?<x>b)|(?<x>c)/`,
38+
errors: [
39+
{
40+
message:
41+
"ES2025 RegExp duplicate named capturing groups are forbidden.",
42+
column: 10,
43+
},
44+
],
45+
},
46+
{
47+
code: String.raw`new RegExp("(?<x>a)|(?<x>b)")`,
48+
errors: [
49+
{
50+
message:
51+
"ES2025 RegExp duplicate named capturing groups are forbidden.",
52+
column: 1,
53+
},
54+
],
55+
},
56+
{
57+
code: String.raw`new RegExp("(?<x>a)|(?<x>b)|(?<x>c)")`,
58+
errors: [
59+
{
60+
message:
61+
"ES2025 RegExp duplicate named capturing groups are forbidden.",
62+
column: 1,
63+
},
64+
],
65+
},
66+
{
67+
code: String.raw`/(?<x>a)|(?<y>b)|(?<x>c)/`,
68+
errors: [
69+
{
70+
message:
71+
"ES2025 RegExp duplicate named capturing groups are forbidden.",
72+
column: 18,
73+
},
74+
],
75+
},
76+
],
77+
})

0 commit comments

Comments
 (0)