Skip to content

Commit 2cab556

Browse files
authored
Fix false positives for disallowNeverMatch option in regexp/no-dupe-disjunctions rule (#83)
1 parent 6c8f466 commit 2cab556

File tree

2 files changed

+39
-65
lines changed

2 files changed

+39
-65
lines changed

lib/utils/regexp-ast/is-covered.ts

Lines changed: 23 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -772,24 +772,41 @@ function isCoveredAnyNode(
772772
return false
773773
}
774774

775+
/* eslint-disable complexity -- X( */
775776
/** Check whether the right nodes is covered by the left nodes. */
776777
function isCoveredAltNodes(
778+
/* eslint-enable complexity -- X( */
777779
left: NormalizedNode[],
778780
right: NormalizedNode[],
779781
options: Options,
780782
) {
781-
// if (options.canOmitRight) {
782-
// return isCoveredAltNodesForCanOmitRight(left, right, options)
783-
// }
783+
let rightLength = right.length
784+
if (options.canOmitRight) {
785+
while (right[rightLength - 1]) {
786+
const re = right[rightLength - 1]
787+
if (re.type === "NormalizedOptional") {
788+
rightLength--
789+
} else {
790+
break
791+
}
792+
}
793+
}
784794
let leftIndex = 0
785795
let rightIndex = 0
786-
while (leftIndex < left.length && rightIndex < right.length) {
796+
while (leftIndex < left.length && rightIndex < rightLength) {
787797
const le = left[leftIndex]
788798
const re = right[rightIndex]
789799

790800
if (re.type === "NormalizedOptional") {
791-
rightIndex++
792-
continue
801+
let leftElement
802+
if (le.type === "NormalizedOptional") {
803+
leftElement = le.element
804+
} else {
805+
leftElement = le
806+
}
807+
if (!isCoveredForNormalizedNode(leftElement, re.element, options)) {
808+
return false
809+
}
793810
} else if (le.type === "NormalizedOptional") {
794811
// Checks if skipped.
795812
const skippedLeftItems = left.slice(leftIndex + 1)
@@ -838,62 +855,3 @@ function isCoveredAltNodes(
838855
}
839856
return leftIndex >= left.length
840857
}
841-
842-
/** Check whether the right nodes is covered by the left nodes. */
843-
// function isCoveredAltNodesForCanOmitRight(
844-
// left: NormalizedNode[],
845-
// right: NormalizedNode[],
846-
// options: Options,
847-
// ) {
848-
// let leftIndex = 0
849-
// let rightIndex = 0
850-
// while (leftIndex < left.length && rightIndex < right.length) {
851-
// const le = left[leftIndex]
852-
// const re = right[rightIndex]
853-
854-
// if (re.type === "NormalizedOptional") {
855-
// rightIndex++
856-
// continue
857-
// } else if (le.type === "NormalizedOptional") {
858-
// // Checks if skipped.
859-
// const skippedLeftItems = left.slice(leftIndex + 1)
860-
// if (
861-
// isCoveredAltNodes(
862-
// skippedLeftItems,
863-
// right.slice(rightIndex),
864-
// options,
865-
// )
866-
// ) {
867-
// return true
868-
// }
869-
// if (!isCoveredForNormalizedNode(le.element, re, options)) {
870-
// // I know it won't match if I skip it.
871-
// return false
872-
// }
873-
// if (le.max >= 2) {
874-
// // Check for multiple iterations.
875-
// if (
876-
// isCoveredAltNodes(
877-
// [le.decrementMax(), ...skippedLeftItems],
878-
// right.slice(rightIndex + 1),
879-
// options,
880-
// )
881-
// ) {
882-
// return true
883-
// }
884-
// }
885-
// } else if (!isCoveredForNormalizedNode(le, re, options)) {
886-
// return false
887-
// }
888-
// leftIndex++
889-
// rightIndex++
890-
// }
891-
// while (leftIndex < left.length) {
892-
// const le = left[leftIndex]
893-
// if (le.type !== "NormalizedOptional") {
894-
// return false
895-
// }
896-
// leftIndex++
897-
// }
898-
// return leftIndex >= left.length
899-
// }

tests/lib/rules/no-dupe-disjunctions.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ tester.run("no-dupe-disjunctions", rule as any, {
2020
`/(?:js|jso?n?)$/`,
2121
`/(?:js|json)abc/`,
2222
`/(?:js|json)?abc/`,
23+
`/(?:yml|ya?ml)$/`,
24+
`/(?:yml|ya?ml)/`,
2325
].reduce(
2426
(acc, x) =>
2527
acc.concat(x, {
@@ -314,5 +316,19 @@ tester.run("no-dupe-disjunctions", rule as any, {
314316
"This disjunction can never match. Its condition is covered by previous conditions in the disjunctions.",
315317
],
316318
},
319+
{
320+
code: `/(?:ya?ml|yml)$/`,
321+
options: [{ disallowNeverMatch: true }],
322+
errors: [
323+
"This disjunction can never match. Its condition is covered by previous conditions in the disjunctions.",
324+
],
325+
},
326+
{
327+
code: `/(?:ya?ml|yml)/`,
328+
options: [{ disallowNeverMatch: true }],
329+
errors: [
330+
"This disjunction can never match. Its condition is covered by previous conditions in the disjunctions.",
331+
],
332+
},
317333
],
318334
})

0 commit comments

Comments
 (0)