Skip to content

Commit

Permalink
feat: add rule no-regexp-duplicate-named-groups (and bump to ES2025) (
Browse files Browse the repository at this point in the history
#32)

* feat: add `no-regexp-v-flag` (and bump to ES2024)

Also:
- fix: ensures no-hashbang-comment rule is in TS 2023
- docs: remove unneeded backticks in no-regexp-s-flag rule docs

* feat: add rule `no-regexp-duplicate-named-groups` (and bump to ES2025)

Also:
- docs: add required escapes to `no-regexp-named-group` docs

---------

Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>
  • Loading branch information
brettz9 and keithamus committed Jul 24, 2024
1 parent 58260bf commit 23b867e
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ for configuration. Here's some examples:
- [no-private-class-fields](./docs/no-private-class-fields.md)
- [no-public-instance-class-fields](./docs/no-public-instance-class-fields.md)
- [no-public-static-class-fields](./docs/no-public-static-class-fields.md)
- [no-regexp-duplicate-named-groups](./docs/no-regexp-duplicate-named-groups.md)
- [no-regexp-lookbehind](./docs/no-regexp-lookbehind.md)
- [no-regexp-named-group](./docs/no-regexp-named-group.md)
- [no-regexp-s-flag](./docs/no-regexp-s-flag.md)
Expand Down
24 changes: 24 additions & 0 deletions docs/no-regexp-duplicate-named-groups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# no-regexp-duplicate-named-groups

This prevents the use of the RegExp duplicate named groups feature

```js
/(?<year>\d{4})-(?<month>\d{2})|(?<month>\d{2})-(?<year>\d{4})/;

new RegExp('(?<year>\\d{4})-(?<month>\\d{2})|(?<month>\\d{2})-(?<year>\\d{4})')
```

These will not be allowed because they are not supported in the following browsers:

- Edge < 125
- Safari < 17
- Firefox < 129
- Chrome < 125


## What is the Fix?

You will have to avoid getting the same name out-of-the-box for an
alternative group.

This can be safely disabled if you intend to compile code with the `@babel/plugin-proposal-duplicate-named-capturing-groups-regex` Babel plugin.
4 changes: 2 additions & 2 deletions docs/no-regexp-named-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This prevents the use of the RegExp named groups feature
```js
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/

new RegExp('(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})')
new RegExp('(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})')
```

These will not be allowed because they are not supported in the following browsers:
Expand All @@ -22,7 +22,7 @@ If readability is the main concern, using non-named groups with array-destructur

```js
// With named:
const {year,month,day} = '2020-01-01'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/).groups
const {year, month, day} = '2020-01-01'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/).groups

// Without named
const [_, year, month, day] = '2020-01-01'.match(/(\d{4})-(\d{2})-(\d{2})/) || []
Expand Down
12 changes: 10 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ createRule(
{ ts: 2024 }
);

// ES2025
createRule(
"no-regexp-duplicate-named-groups",
"edge < 125, safari < 17, firefox < 129, chrome < 125",
"disallow the use of RegExp duplicate named groups",
{ ts: 2025 }
);

// Proposals...
createRule(
"no-do-expression",
Expand All @@ -247,7 +255,7 @@ createRule(

module.exports.configs.recommended = {
plugins: ["escompat"],
parserOptions: { ecmaVersion: 2024 },
parserOptions: { ecmaVersion: 2025 },
rules: Object.keys(module.exports.rules).reduce(
(o, r) => ((o["escompat/" + r] = ["error"]), o),
{}
Expand All @@ -260,7 +268,7 @@ module.exports.configs["flat/recommended"] = {
escompat: module.exports
},
languageOptions: {
ecmaVersion: 2024
ecmaVersion: 2025
},
rules: Object.keys(module.exports.rules).reduce(
(o, r) => ((o["escompat/" + r] = ["error"]), o),
Expand Down
30 changes: 30 additions & 0 deletions lib/rules/no-regexp-duplicate-named-groups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const hasDuplicateNamedGroups = s => /(\(\?<[_$\w]*?)>.*?\1>/.test(s)

module.exports = (context, badBrowser) => ({
'Literal[regex]'(node) {
if (hasDuplicateNamedGroups(node.regex.pattern)) {
context.report(node, `RegExp duplicate named groups are not supported in ${badBrowser}`)
}
},
'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) {
const [source] = node.arguments;
if (
source &&
(
(
source.type === 'Literal' &&
typeof source.value === 'string' &&
hasDuplicateNamedGroups(source.value)
) ||
(
source.type === 'TemplateLiteral' &&
source.quasis.some(({value: {raw}}) => hasDuplicateNamedGroups(raw))
)
)
) {
context.report(node, `RegExp duplicate named groups are not supported in ${badBrowser}`)
}
}
})
52 changes: 52 additions & 0 deletions test/no-regexp-duplicate-named-groups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';

const rule = require('../lib/index').rules['no-regexp-duplicate-named-groups']
const RuleTester = require('eslint').RuleTester

const ruleTester = new RuleTester({languageOptions: {ecmaVersion: 2025}})

ruleTester.run('no-regexp-duplicate-named-groups', rule, {
valid: [
{code: '/(?:a)/'},
{code: '/(?:a)/g'},
{code: 'RegExp("(?:a)b")'},
{code: 'RegExp("(?:a)b", "g")'},
{code: '/(?<name>a)/'},
{code: 'RegExp("(?<name>a)")'},
{code: '/(?<name>a)|(?<anotherName>a)/'},
],
invalid: [
{
code: '/(?<name>a)|(?<name>b)/',
errors: [
{
message: 'RegExp duplicate named groups are not supported in undefined'
}
]
},
{
code: 'new RegExp("(?<name>a)|(?<name>b)")',
errors: [
{
message: 'RegExp duplicate named groups are not supported in undefined'
}
]
},
{
code: '/(?<$name>a)|(?<$name>b)/',
errors: [
{
message: 'RegExp duplicate named groups are not supported in undefined'
}
]
},
{
code: '/(?<_name>)|(?<_name>)/',
errors: [
{
message: 'RegExp duplicate named groups are not supported in undefined'
}
]
},
]
})

0 comments on commit 23b867e

Please sign in to comment.