Skip to content

Commit f6a3036

Browse files
Update refa & co (#568)
* Updated refa and co * Fixed some type errors * More fixes * More fixes * More fixes * Create cyan-waves-notice.md --------- Co-authored-by: Yosuke Ota <otameshiyo23@gmail.com>
1 parent 958b4a6 commit f6a3036

32 files changed

+355
-237
lines changed

.changeset/cyan-waves-notice.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+
Update refa, regexp-ast-analysis, and scslre

lib/rules/confusing-quantifier.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@ export default createRule("confusing-quantifier", {
2929
*/
3030
function createVisitor({
3131
node,
32+
flags,
3233
getRegexpLocation,
3334
}: RegExpContext): RegExpVisitor.Handlers {
3435
return {
3536
onQuantifierEnter(qNode) {
36-
if (qNode.min > 0 && isPotentiallyEmpty(qNode.element)) {
37+
if (
38+
qNode.min > 0 &&
39+
isPotentiallyEmpty(qNode.element, flags)
40+
) {
3741
const proposal = quantToString({ ...qNode, min: 0 })
3842
context.report({
3943
node,

lib/rules/negation.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ export default createRule("negation", {
5353
// All other character sets are either case-invariant
5454
// (/./, /\s/, /\d/) or inconsistent (/\w/).
5555

56+
// FIXME: TS Error
57+
// @ts-expect-error -- FIXME
5658
const ccSet = toCharSet(ccNode, flags)
5759

5860
const negatedElementSet = toCharSet(
61+
// FIXME: TS Error
62+
// @ts-expect-error -- FIXME
5963
{
6064
...element,
61-
// FIXME: TS Error
62-
// @ts-expect-error -- FIXME
6365
negate: !element.negate,
6466
},
6567
flags,

lib/rules/no-contradiction-with-assertion.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function isTrivialAssertion(
4343
}
4444

4545
if (assertion.kind === "lookahead" || assertion.kind === "lookbehind") {
46-
if (isPotentiallyEmpty(assertion.alternatives)) {
46+
if (isPotentiallyEmpty(assertion.alternatives, flags)) {
4747
// The assertion is guaranteed to trivially accept/reject.
4848
return true
4949
}
@@ -80,6 +80,7 @@ function isTrivialAssertion(
8080
function* getNextElements(
8181
start: Element,
8282
dir: MatchingDirection,
83+
flags: ReadonlyFlags,
8384
): Iterable<Element> {
8485
let element = start
8586

@@ -110,7 +111,7 @@ function* getNextElements(
110111
for (let i = index + inc; i >= 0 && i < elements.length; i += inc) {
111112
const e = elements[i]
112113
yield e
113-
if (!isZeroLength(e)) {
114+
if (!isZeroLength(e, flags)) {
114115
return
115116
}
116117
}
@@ -142,6 +143,7 @@ function tryFindContradictionIn(
142143
element: Element,
143144
dir: MatchingDirection,
144145
condition: (e: Element | Alternative) => boolean,
146+
flags: ReadonlyFlags,
145147
): boolean {
146148
if (condition(element)) {
147149
return true
@@ -151,7 +153,7 @@ function tryFindContradictionIn(
151153
// Go into the alternatives of groups
152154
let some = false
153155
element.alternatives.forEach((a) => {
154-
if (tryFindContradictionInAlternative(a, dir, condition)) {
156+
if (tryFindContradictionInAlternative(a, dir, condition, flags)) {
155157
some = true
156158
}
157159
})
@@ -160,7 +162,7 @@ function tryFindContradictionIn(
160162

161163
if (element.type === "Quantifier" && element.max === 1) {
162164
// Go into the element of quantifiers if their maximum is 1
163-
return tryFindContradictionIn(element.element, dir, condition)
165+
return tryFindContradictionIn(element.element, dir, condition, flags)
164166
}
165167

166168
if (
@@ -173,7 +175,7 @@ function tryFindContradictionIn(
173175
// Since we don't consume characters, we want to keep going even if we
174176
// find a contradiction inside the lookaround.
175177
element.alternatives.forEach((a) =>
176-
tryFindContradictionInAlternative(a, dir, condition),
178+
tryFindContradictionInAlternative(a, dir, condition, flags),
177179
)
178180
}
179181

@@ -188,6 +190,7 @@ function tryFindContradictionInAlternative(
188190
alternative: Alternative,
189191
dir: MatchingDirection,
190192
condition: (e: Element | Alternative) => boolean,
193+
flags: ReadonlyFlags,
191194
): boolean {
192195
if (condition(alternative)) {
193196
return true
@@ -199,10 +202,10 @@ function tryFindContradictionInAlternative(
199202
const inc = dir === "ltr" ? 1 : -1
200203
for (let i = first; i >= 0 && i < elements.length; i += inc) {
201204
const e = elements[i]
202-
if (tryFindContradictionIn(e, dir, condition)) {
205+
if (tryFindContradictionIn(e, dir, condition, flags)) {
203206
return true
204207
}
205-
if (!isZeroLength(e)) {
208+
if (!isZeroLength(e, flags)) {
206209
break
207210
}
208211
}
@@ -271,8 +274,10 @@ export default createRule("no-contradiction-with-assertion", {
271274
getFirstConsumedChar(assertion, dir, flags),
272275
)
273276

274-
for (const element of getNextElements(assertion, dir)) {
275-
if (tryFindContradictionIn(element, dir, contradicts)) {
277+
for (const element of getNextElements(assertion, dir, flags)) {
278+
if (
279+
tryFindContradictionIn(element, dir, contradicts, flags)
280+
) {
276281
break
277282
}
278283
}

lib/rules/no-dupe-characters-character-class.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
defineRegexpVisitor,
1616
toCharSetSource,
1717
fixRemoveCharacterClassElement,
18+
assertValidFlags,
1819
} from "../utils"
1920
import type { CharRange, CharSet } from "refa"
2021
import { JS } from "refa"
@@ -276,6 +277,8 @@ export default createRule("no-dupe-characters-character-class", {
276277
// report characters that are already matched by some range or set
277278
for (const char of characters) {
278279
for (const other of rangesAndSets) {
280+
// FIXME: TS Error
281+
// @ts-expect-error -- FIXME
279282
if (toCharSet(other, flags).has(char.value)) {
280283
reportSubset(regexpContext, char, other)
281284
subsets.add(char)
@@ -292,7 +295,11 @@ export default createRule("no-dupe-characters-character-class", {
292295
}
293296

294297
if (
298+
// FIXME: TS Error
299+
// @ts-expect-error -- FIXME
295300
toCharSet(element, flags).isSubsetOf(
301+
// FIXME: TS Error
302+
// @ts-expect-error -- FIXME
296303
toCharSet(other, flags),
297304
)
298305
) {
@@ -317,9 +324,13 @@ export default createRule("no-dupe-characters-character-class", {
317324
const totalOthers = characterTotal.union(
318325
...rangesAndSets
319326
.filter((e) => !subsets.has(e) && e !== element)
327+
// FIXME: TS Error
328+
// @ts-expect-error -- FIXME
320329
.map((e) => toCharSet(e, flags)),
321330
)
322331

332+
// FIXME: TS Error
333+
// @ts-expect-error -- FIXME
323334
const elementCharSet = toCharSet(element, flags)
324335
if (elementCharSet.isSubsetOf(totalOthers)) {
325336
const superSetElements = ccNode.elements
@@ -359,6 +370,8 @@ export default createRule("no-dupe-characters-character-class", {
359370
const intersection = toCharSet(
360371
range,
361372
flags,
373+
// FIXME: TS Error
374+
// @ts-expect-error -- FIXME
362375
).intersect(toCharSet(other, flags))
363376
if (intersection.isEmpty) {
364377
continue
@@ -379,6 +392,7 @@ export default createRule("no-dupe-characters-character-class", {
379392
// (see GH #189).
380393
// to prevent this, we will create a new CharSet
381394
// using `createCharSet`
395+
assertValidFlags(flags)
382396
const interest = JS.createCharSet(
383397
interestingRanges,
384398
flags,

lib/rules/no-dupe-disjunctions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
defineRegexpVisitor,
1515
fixRemoveCharacterClassElement,
1616
fixRemoveAlternative,
17+
assertValidFlags,
1718
} from "../utils"
1819
import { getParser, isCoveredNode, isEqualNodes } from "../utils/regexp-ast"
1920
import type { Expression, FiniteAutomaton, NoParent, ReadonlyNFA } from "refa"
@@ -434,6 +435,7 @@ function getPartialSubsetRelation(
434435
*/
435436
function faToSource(fa: FiniteAutomaton, flags: ReadonlyFlags): string {
436437
try {
438+
assertValidFlags(flags)
437439
return JS.toLiteral(fa.toRegex(), { flags }).source
438440
} catch (_error) {
439441
return "<ERROR>"

lib/rules/no-empty-capturing-group.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ export default createRule("no-empty-capturing-group", {
2222
*/
2323
function createVisitor({
2424
node,
25+
flags,
2526
getRegexpLocation,
2627
}: RegExpContext): RegExpVisitor.Handlers {
2728
return {
2829
onCapturingGroupEnter(cgNode) {
29-
if (isZeroLength(cgNode)) {
30+
if (isZeroLength(cgNode, flags)) {
3031
context.report({
3132
node,
3233
loc: getRegexpLocation(cgNode),

lib/rules/no-empty-lookarounds-assertion.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default createRule("no-empty-lookarounds-assertion", {
2424
*/
2525
function createVisitor({
2626
node,
27+
flags,
2728
getRegexpLocation,
2829
}: RegExpContext): RegExpVisitor.Handlers {
2930
return {
@@ -35,7 +36,7 @@ export default createRule("no-empty-lookarounds-assertion", {
3536
return
3637
}
3738

38-
if (isPotentiallyEmpty(aNode.alternatives)) {
39+
if (isPotentiallyEmpty(aNode.alternatives, flags)) {
3940
context.report({
4041
node,
4142
loc: getRegexpLocation(aNode),

lib/rules/no-misleading-capturing-group.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* eslint-disable eslint-comments/disable-enable-pair -- x */
2+
/* eslint-disable complexity -- x */
13
import type { RegExpVisitor } from "@eslint-community/regexpp/visitor"
24
import type {
35
Alternative,
@@ -48,10 +50,11 @@ function* iterReverse<T>(array: readonly T[]): Iterable<T> {
4850
function* getStartQuantifiers(
4951
root: Element | Alternative | Alternative[],
5052
direction: MatchingDirection,
53+
flags: ReadonlyFlags,
5154
): Iterable<Quantifier> {
5255
if (Array.isArray(root)) {
5356
for (const a of root) {
54-
yield* getStartQuantifiers(a, direction)
57+
yield* getStartQuantifiers(a, direction, flags)
5558
}
5659
return
5760
}
@@ -60,6 +63,7 @@ function* getStartQuantifiers(
6063
case "Character":
6164
case "CharacterClass":
6265
case "CharacterSet":
66+
case "ExpressionCharacterClass":
6367
case "Backreference":
6468
// we can't go into terminals
6569
break
@@ -71,8 +75,8 @@ function* getStartQuantifiers(
7175
const elements =
7276
direction === "ltr" ? root.elements : iterReverse(root.elements)
7377
for (const e of elements) {
74-
if (isEmpty(e)) continue
75-
yield* getStartQuantifiers(e, direction)
78+
if (isEmpty(e, flags)) continue
79+
yield* getStartQuantifiers(e, direction, flags)
7680
break
7781
}
7882
break
@@ -82,17 +86,15 @@ function* getStartQuantifiers(
8286
// of this rule
8387
break
8488
case "Group":
85-
yield* getStartQuantifiers(root.alternatives, direction)
89+
yield* getStartQuantifiers(root.alternatives, direction, flags)
8690
break
8791
case "Quantifier":
8892
yield root
8993
if (root.max === 1) {
90-
yield* getStartQuantifiers(root.element, direction)
94+
yield* getStartQuantifiers(root.element, direction, flags)
9195
}
9296
break
9397
default:
94-
// FIXME: TS Error
95-
// @ts-expect-error -- FIXME
9698
yield assertNever(root)
9799
}
98100
}
@@ -168,6 +170,9 @@ function uncachedGetSingleRepeatedChar(
168170
case "Character":
169171
case "CharacterClass":
170172
case "CharacterSet":
173+
case "ExpressionCharacterClass":
174+
// FIXME: TS Error
175+
// @ts-expect-error -- FIXME
171176
return toCharSet(element, flags)
172177

173178
case "CapturingGroup":
@@ -181,8 +186,6 @@ function uncachedGetSingleRepeatedChar(
181186
return getSingleRepeatedChar(element.element, flags, cache)
182187

183188
default:
184-
// FIXME: TS Error
185-
// @ts-expect-error -- FIXME
186189
return assertNever(element)
187190
}
188191
}
@@ -226,6 +229,7 @@ function getTradingQuantifiersAfter(
226229
case "Character":
227230
case "CharacterClass":
228231
case "CharacterSet":
232+
case "ExpressionCharacterClass":
229233
return state.intersect(
230234
getSingleRepeatedChar(element, flags),
231235
)
@@ -236,8 +240,6 @@ function getTradingQuantifiersAfter(
236240
return state
237241

238242
default:
239-
// FIXME: TS Error
240-
// @ts-expect-error -- FIXME
241243
return assertNever(element)
242244
}
243245
},
@@ -329,6 +331,7 @@ export default createRule("no-misleading-capturing-group", {
329331
const startQuantifiers = getStartQuantifiers(
330332
capturingGroup.alternatives,
331333
direction,
334+
flags,
332335
)
333336

334337
for (const quantifier of startQuantifiers) {
@@ -409,6 +412,7 @@ export default createRule("no-misleading-capturing-group", {
409412
const endQuantifiers = getStartQuantifiers(
410413
capturingGroup.alternatives,
411414
invertMatchingDirection(direction),
415+
flags,
412416
)
413417

414418
for (const quantifier of endQuantifiers) {
@@ -439,7 +443,10 @@ export default createRule("no-misleading-capturing-group", {
439443
}
440444
if (
441445
trader.quant.min >= 1 &&
442-
!isPotentiallyZeroLength(trader.quant.element)
446+
!isPotentiallyZeroLength(
447+
trader.quant.element,
448+
flags,
449+
)
443450
)
444451
context.report({
445452
node,

0 commit comments

Comments
 (0)