Skip to content

Commit 7e5cb0b

Browse files
authored
feat: Add allows option to prefer-quantifier rule (#835)
* feat: Add `allows` property to `prefer-quantifier` rule * docs: Document `allows` option of `prefer-quantifier` rule * chore: Add changeset
1 parent 81e1cf1 commit 7e5cb0b

File tree

5 files changed

+111
-4
lines changed

5 files changed

+111
-4
lines changed

.changeset/chilled-doors-wave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-regexp": minor
3+
---
4+
5+
Add `allows` option to `prefer-quantifier` rule

docs/rules/prefer-quantifier.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,33 @@ var foo = /\d\d\d\d-\d\d-\d\d/;
3333

3434
## :wrench: Options
3535

36-
Nothing.
36+
```json
37+
{
38+
"regexp/prefer-quantifier": ["error", {
39+
"allows": ["www", "\\d\\d"]
40+
}]
41+
}
42+
```
43+
44+
- `"allows"` ... Array of allowed patterns.
45+
46+
### `{ "allows": ["www", "\\d\\d"] }`
47+
48+
<eslint-code-block fix>
49+
50+
```js
51+
/* eslint regexp/prefer-quantifier: ["error", { "allows": ["www", "\\d\\d"] }] */
52+
53+
/* ✓ GOOD */
54+
var foo = /(?:www\.)?(.*)/;
55+
var foo = /\d\d:\d\d/;
56+
57+
/* ✗ BAD */
58+
var foo = /wwww/;
59+
var foo = /\d\d\d\d/;
60+
```
61+
62+
</eslint-code-block>
3763

3864
## :rocket: Version
3965

lib/rules/prefer-quantifier.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Character, CharacterSet } from "@eslint-community/regexpp/ast"
22
import type { RegExpVisitor } from "@eslint-community/regexpp/visitor"
3+
import type { ObjectOption } from "../types"
34
import type { RegExpContext } from "../utils"
45
import {
56
createRule,
@@ -22,9 +23,12 @@ class CharBuffer {
2223

2324
public equalChar: (element: CharTarget) => boolean
2425

25-
public constructor(target: CharTarget) {
26+
private readonly allows: string[]
27+
28+
public constructor(target: CharTarget, allows: string[]) {
2629
this.target = target
2730
this.elements = [target]
31+
this.allows = allows
2832

2933
this.times = 1
3034

@@ -57,10 +61,18 @@ class CharBuffer {
5761
this.times += 1
5862
}
5963

64+
private get bufferRawContents() {
65+
return this.elements.reduce((acc, element) => acc + element.raw, "")
66+
}
67+
6068
public isValid(): boolean {
6169
if (this.elements.length < 2) {
6270
return true
6371
}
72+
if (this.allows.includes(this.bufferRawContents)) {
73+
return true
74+
}
75+
6476
let charKind: "digit" | "letter" | "symbol" | null = null
6577
for (const element of this.elements) {
6678
if (element.type === "Character") {
@@ -105,14 +117,30 @@ export default createRule("prefer-quantifier", {
105117
recommended: false,
106118
},
107119
fixable: "code",
108-
schema: [],
120+
schema: [
121+
{
122+
type: "object",
123+
properties: {
124+
allows: {
125+
type: "array",
126+
items: {
127+
type: "string",
128+
},
129+
},
130+
},
131+
additionalProperties: false,
132+
},
133+
],
109134
messages: {
110135
unexpected:
111136
"Unexpected consecutive same {{type}}. Use '{{quantifier}}' instead.",
112137
},
113138
type: "suggestion", // "problem",
114139
},
115140
create(context) {
141+
const allows: string[] =
142+
(context.options[0] as ObjectOption)?.allows ?? []
143+
116144
function createVisitor({
117145
node,
118146
patternSource,
@@ -129,7 +157,7 @@ export default createRule("prefer-quantifier", {
129157
charBuffer.addElement(element)
130158
} else {
131159
validateBuffer(charBuffer)
132-
charBuffer = new CharBuffer(element)
160+
charBuffer = new CharBuffer(element, allows)
133161
}
134162
} else {
135163
validateBuffer(charBuffer)

tests/lib/rules/__snapshots__/prefer-quantifier.ts.eslintsnap

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,35 @@ Output: unchanged
162162

163163
[1] Unexpected consecutive same character class escapes. Use '{2}' instead.
164164
---
165+
166+
167+
Test: prefer-quantifier >> invalid
168+
Options:
169+
- allows:
170+
- www
171+
172+
Code:
173+
1 | /wwww/
174+
| ^~~~ [1]
175+
176+
Output:
177+
1 | /w{4}/
178+
179+
[1] Unexpected consecutive same characters. Use '{4}' instead.
180+
---
181+
182+
183+
Test: prefer-quantifier >> invalid
184+
Options:
185+
- allows:
186+
- \d\d
187+
188+
Code:
189+
1 | /\d\d-\d\d\d\d/
190+
| ^~~~~~~~ [1]
191+
192+
Output:
193+
1 | /\d\d-\d{4}/
194+
195+
[1] Unexpected consecutive same character class escapes. Use '{4}' instead.
196+
---

tests/lib/rules/prefer-quantifier.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ tester.run("prefer-quantifier", rule as any, {
1919
`/---/`,
2020
`/a.{1,3}?.{2,4}c/`,
2121
`/a.{1,3}.{2,4}?c/`,
22+
{
23+
code: `/www/`,
24+
options: [{ allows: ["www"] }],
25+
},
26+
{
27+
code: `/\\d\\d/`,
28+
options: [{ allows: [`\\d\\d`] }],
29+
},
2230
],
2331
invalid: [
2432
`/\\d\\d/`,
@@ -39,5 +47,13 @@ tester.run("prefer-quantifier", rule as any, {
3947
const s = "\\\\d"+"\\\\d"
4048
new RegExp(s)
4149
`,
50+
{
51+
code: `/wwww/`,
52+
options: [{ allows: ["www"] }],
53+
},
54+
{
55+
code: String.raw`/\d\d-\d\d\d\d/`,
56+
options: [{ allows: [`\\d\\d`] }],
57+
},
4258
],
4359
})

0 commit comments

Comments
 (0)