Skip to content

Commit cad7d1c

Browse files
authored
Add regexp/no-useless-non-greedy rule (#31)
1 parent 49f6c89 commit cad7d1c

File tree

7 files changed

+162
-1
lines changed

7 files changed

+162
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ The rules with the following star :star: are included in the `plugin:regexp/reco
9090
| [regexp/no-useless-backreference](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-backreference.html) | disallow useless backreferences in regular expressions | |
9191
| [regexp/no-useless-character-class](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-character-class.html) | disallow character class with one character | :wrench: |
9292
| [regexp/no-useless-exactly-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-exactly-quantifier.html) | disallow unnecessary exactly quantifier | :star: |
93+
| [regexp/no-useless-non-greedy](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-non-greedy.html) | disallow unnecessary quantifier non-greedy (`?`) | :wrench: |
9394
| [regexp/no-useless-two-nums-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-two-nums-quantifier.html) | disallow unnecessary `{n,m}` quantifier | :star: |
9495
| [regexp/prefer-d](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-d.html) | enforce using `\d` | :star::wrench: |
9596
| [regexp/prefer-plus-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-plus-quantifier.html) | enforce using `+` quantifier | :star::wrench: |

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ The rules with the following star :star: are included in the `plugin:regexp/reco
2222
| [regexp/no-useless-backreference](./no-useless-backreference.md) | disallow useless backreferences in regular expressions | |
2323
| [regexp/no-useless-character-class](./no-useless-character-class.md) | disallow character class with one character | :wrench: |
2424
| [regexp/no-useless-exactly-quantifier](./no-useless-exactly-quantifier.md) | disallow unnecessary exactly quantifier | :star: |
25+
| [regexp/no-useless-non-greedy](./no-useless-non-greedy.md) | disallow unnecessary quantifier non-greedy (`?`) | :wrench: |
2526
| [regexp/no-useless-two-nums-quantifier](./no-useless-two-nums-quantifier.md) | disallow unnecessary `{n,m}` quantifier | :star: |
2627
| [regexp/prefer-d](./prefer-d.md) | enforce using `\d` | :star::wrench: |
2728
| [regexp/prefer-plus-quantifier](./prefer-plus-quantifier.md) | enforce using `+` quantifier | :star::wrench: |

docs/rules/no-useless-non-greedy.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "regexp/no-useless-non-greedy"
5+
description: "disallow unnecessary quantifier non-greedy (`?`)"
6+
---
7+
# regexp/no-useless-non-greedy
8+
9+
> disallow unnecessary quantifier non-greedy (`?`)
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
13+
14+
## :book: Rule Details
15+
16+
This rule reports unnecessary quantifier non-greedy (`?`).
17+
18+
<eslint-code-block fix>
19+
20+
```js
21+
/* eslint regexp/no-useless-non-greedy: "error" */
22+
23+
/* ✓ GOOD */
24+
var foo = /a*?/;
25+
var foo = /a+?/;
26+
var foo = /a{4,}?/;
27+
var foo = /a{2,4}?/;
28+
29+
/* ✗ BAD */
30+
var foo = /a{1}?/;
31+
var foo = /a{4}?/;
32+
var foo = /a{2,2}?/;
33+
```
34+
35+
</eslint-code-block>
36+
37+
## :wrench: Options
38+
39+
Nothing.
40+
41+
## :mag: Implementation
42+
43+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/lib/rules/no-useless-non-greedy.ts)
44+
- [Test source](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/tests/lib/rules/no-useless-non-greedy.ts)

docs/rules/no-useless-two-nums-quantifier.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ var foo = /a{1,5}/;
2626
var foo = /a{1,}/;
2727
var foo = /a{2}/;
2828

29-
3029
/* ✗ BAD */
3130
var foo = /a{0,0}/;
3231
var foo = /a{1,1}/;

lib/rules/no-useless-non-greedy.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import type { Expression } from "estree"
2+
import type { RegExpVisitor } from "regexpp/visitor"
3+
import {
4+
createRule,
5+
defineRegexpVisitor,
6+
getRegexpLocation,
7+
getRegexpRange,
8+
} from "../utils"
9+
10+
export default createRule("no-useless-non-greedy", {
11+
meta: {
12+
docs: {
13+
description: "disallow unnecessary quantifier non-greedy (`?`)",
14+
// TODO In the major version
15+
// recommended: true,
16+
recommended: false,
17+
},
18+
fixable: "code",
19+
schema: [],
20+
messages: {
21+
unexpected: "Unexpected quantifier non-greedy.",
22+
},
23+
type: "suggestion", // "problem",
24+
},
25+
create(context) {
26+
const sourceCode = context.getSourceCode()
27+
28+
/**
29+
* Create visitor
30+
* @param node
31+
*/
32+
function createVisitor(node: Expression): RegExpVisitor.Handlers {
33+
return {
34+
onQuantifierEnter(qNode) {
35+
if (qNode.greedy === false && qNode.min === qNode.max) {
36+
const offset = qNode.raw.length - 1
37+
context.report({
38+
node,
39+
loc: getRegexpLocation(sourceCode, node, qNode, [
40+
offset,
41+
offset + 1,
42+
]),
43+
messageId: "unexpected",
44+
fix(fixer) {
45+
const range = getRegexpRange(
46+
sourceCode,
47+
node,
48+
qNode,
49+
)
50+
if (range == null) {
51+
return null
52+
}
53+
return fixer.removeRange([
54+
range[1] - 1,
55+
range[1],
56+
])
57+
},
58+
})
59+
}
60+
},
61+
}
62+
}
63+
64+
return defineRegexpVisitor(context, {
65+
createVisitor,
66+
})
67+
},
68+
})

lib/utils/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import noOctal from "../rules/no-octal"
1010
import noUselessBackreference from "../rules/no-useless-backreference"
1111
import noUselessCharacterClass from "../rules/no-useless-character-class"
1212
import noUselessExactlyQuantifier from "../rules/no-useless-exactly-quantifier"
13+
import noUselessNonGreedy from "../rules/no-useless-non-greedy"
1314
import noUselessTwoNumsQuantifier from "../rules/no-useless-two-nums-quantifier"
1415
import preferD from "../rules/prefer-d"
1516
import preferPlusQuantifier from "../rules/prefer-plus-quantifier"
@@ -31,6 +32,7 @@ export const rules = [
3132
noUselessBackreference,
3233
noUselessCharacterClass,
3334
noUselessExactlyQuantifier,
35+
noUselessNonGreedy,
3436
noUselessTwoNumsQuantifier,
3537
preferD,
3638
preferPlusQuantifier,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { RuleTester } from "eslint"
2+
import rule from "../../../lib/rules/no-useless-non-greedy"
3+
4+
const tester = new RuleTester({
5+
parserOptions: {
6+
ecmaVersion: 2020,
7+
sourceType: "module",
8+
},
9+
})
10+
11+
tester.run("no-useless-non-greedy", rule as any, {
12+
valid: [`/a*?/`, `/a+?/`, `/a{4,}?/`, `/a{2,4}?/`, `/a{2,2}/`, `/a{3}/`],
13+
invalid: [
14+
{
15+
code: `/a{1}?/`,
16+
output: `/a{1}/`,
17+
errors: [
18+
{
19+
message: "Unexpected quantifier non-greedy.",
20+
line: 1,
21+
column: 6,
22+
endLine: 1,
23+
endColumn: 7,
24+
},
25+
],
26+
},
27+
{
28+
code: `/a{4}?/`,
29+
output: `/a{4}/`,
30+
errors: [
31+
{
32+
message: "Unexpected quantifier non-greedy.",
33+
line: 1,
34+
column: 6,
35+
endLine: 1,
36+
endColumn: 7,
37+
},
38+
],
39+
},
40+
{
41+
code: `/a{2,2}?/`,
42+
output: `/a{2,2}/`,
43+
errors: ["Unexpected quantifier non-greedy."],
44+
},
45+
],
46+
})

0 commit comments

Comments
 (0)