Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add regexp/simplify-set-operations rule #595

Merged
merged 16 commits into from
Oct 2, 2023
5 changes: 5 additions & 0 deletions .changeset/early-islands-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-regexp": minor
---

Add `regexp/require-reduce-negation` rule
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ The `plugin:regexp/all` config enables all rules. It's meant for testing, not fo
| [prefer-range](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-range.html) | enforce using character class range | ✅ | | 🔧 | |
| [prefer-regexp-exec](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-regexp-exec.html) | enforce that `RegExp#exec` is used instead of `String#match` if no global flag is provided | | | | |
| [prefer-regexp-test](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-regexp-test.html) | enforce that `RegExp#test` is used instead of `String#match` and `RegExp#exec` | | | 🔧 | |
| [require-reduce-negation](https://ota-meshi.github.io/eslint-plugin-regexp/rules/require-reduce-negation.html) | require to reduce negation of character classes | ✅ | | 🔧 | |
| [require-unicode-regexp](https://ota-meshi.github.io/eslint-plugin-regexp/rules/require-unicode-regexp.html) | enforce the use of the `u` flag | | | 🔧 | |
| [sort-alternatives](https://ota-meshi.github.io/eslint-plugin-regexp/rules/sort-alternatives.html) | sort alternatives if order doesn't matter | | | 🔧 | |
| [use-ignore-case](https://ota-meshi.github.io/eslint-plugin-regexp/rules/use-ignore-case.html) | use the `i` flag if it simplifies the pattern | ✅ | | 🔧 | |
Expand Down
1 change: 1 addition & 0 deletions docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ sidebarDepth: 0
| [prefer-range](prefer-range.md) | enforce using character class range | ✅ | | 🔧 | |
| [prefer-regexp-exec](prefer-regexp-exec.md) | enforce that `RegExp#exec` is used instead of `String#match` if no global flag is provided | | | | |
| [prefer-regexp-test](prefer-regexp-test.md) | enforce that `RegExp#test` is used instead of `String#match` and `RegExp#exec` | | | 🔧 | |
| [require-reduce-negation](require-reduce-negation.md) | require to reduce negation of character classes | ✅ | | 🔧 | |
| [require-unicode-regexp](require-unicode-regexp.md) | enforce the use of the `u` flag | | | 🔧 | |
| [sort-alternatives](sort-alternatives.md) | sort alternatives if order doesn't matter | | | 🔧 | |
| [use-ignore-case](use-ignore-case.md) | use the `i` flag if it simplifies the pattern | ✅ | | 🔧 | |
Expand Down
6 changes: 6 additions & 0 deletions docs/rules/negation.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ var foo = /[^\P{ASCII}]/u

Nothing.

## :couple: Related rules

- [regexp/require-reduce-negation]

[regexp/require-reduce-negation]: ./require-reduce-negation.md

## :rocket: Version

This rule was introduced in eslint-plugin-regexp v0.4.0
Expand Down
92 changes: 92 additions & 0 deletions docs/rules/require-reduce-negation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "regexp/require-reduce-negation"
description: "require to reduce negation of character classes"
---
# regexp/require-reduce-negation

💼 This rule is enabled in the ✅ `plugin:regexp/recommended` config.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

> require to reduce negation of character classes

## :book: Rule Details

This rule is aimed at optimizing patterns by reducing the negation (complement) representation of character classes (with `v` flag).

<eslint-code-block fix>

```js
/* eslint regexp/require-reduce-negation: "error" */

/* ✗ BAD */
var re = /[^[^abc]]/v; // -> /[abc]/v
var re = /[^\D]/u; // -> /[\d]/u
RunDevelopment marked this conversation as resolved.
Show resolved Hide resolved
var re = /[a&&[^b]]/v; // -> /[a--b]/v
var re = /[[^b]&&a]/v; // -> /[a--b]/v
var re = /[a--[^b]]/v; // -> /[a&&b]/v
var re = /[[^a]&&[^b]]/v; // -> /[^ab]/v
var re = /[[^a][^b]]/v; // -> /[^a&&b]/v

/* ✓ GOOD */
var re = /[abc]/v;
var re = /[\d]/u;
var re = /[\D]/u;
var re = /[a--b]/v;
var re = /[a&&b]/v;
var re = /[^ab]/v;
var re = /[^a&&b]/v;
```

</eslint-code-block>

This rule attempts to reduce complements in several ways:

### Double negation elimination

This rule look for patterns that can eliminate double negatives, report on them, and auto-fix them.\
For example, `/[^[^abc]]/v` is equivalent to `/[abc]/v`.

See <https://en.wikipedia.org/wiki/Double_negation#Elimination_and_introduction>.

### De Morgan's laws

This rule uses De Morgan's laws to look for patterns that can convert multiple negations into a single negation, reports on them, auto-fix them.\
For example, `/[[^a]&&[^b]]/v` is equivalent to `/[^ab]/v`, `/[[^a][^b]]/v` is equivalent to `/[^a&&b]/v`.

See <https://en.wikipedia.org/wiki/De_Morgan's_laws>.

### Conversion from the intersection to the subtraction

Intersection sets with complement operands can be converted to difference sets.\
The rule looks for character class intersection with negation operands, reports on them, auto-fix them.\
For example, `/[a&&[^b]]/v` is equivalent to `/[a--b]/v`, `/[[^a]&&b]/v` is equivalent to `/[b--a]/v`.

### Conversion from the subtraction to the intersection

Difference set with a complement operand on the right side can be converted to intersection sets.\
The rule looks for character class subtraction with negation operand on the right side, reports on them, auto-fix them.\
For example, `/[a--[^b]]/v` is equivalent to `/[a&&b]/v`.

## :wrench: Options

Nothing.

## :couple: Related rules

- [regexp/negation]

[regexp/negation]: ./negation.md

## :rocket: Version

:exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>

## :mag: Implementation

- [Rule source](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/lib/rules/require-reduce-negation.ts)
- [Test source](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/tests/lib/rules/require-reduce-negation.ts)
1 change: 1 addition & 0 deletions lib/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const rules = {
"regexp/prefer-star-quantifier": "error",
"regexp/prefer-unicode-codepoint-escapes": "error",
"regexp/prefer-w": "error",
"regexp/require-reduce-negation": "error",
"regexp/sort-flags": "error",
"regexp/strict": "error",
"regexp/use-ignore-case": "error",
Expand Down
Loading
Loading