Skip to content

Commit 6950b0a

Browse files
committed
fix(sort-regexp): skip character class sorting with v flag
1 parent 6f2e7c0 commit 6950b0a

File tree

2 files changed

+140
-1
lines changed

2 files changed

+140
-1
lines changed

rules/sort-regexp.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ export default createEslintRule<Options, MessageId>({
234234
return
235235
}
236236

237+
if (literalNode.regex.flags.includes('v')) {
238+
return
239+
}
240+
237241
let sortedElements = [...elements].toSorted((a, b) => {
238242
let aKey = getCharacterClassElementSortKey(a)
239243
let bKey = getCharacterClassElementSortKey(b)

test/rules/sort-regexp.test.ts

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Cspell:ignore gimsu igmus yusmig ysumgi Ωmega Δelta */
1+
/* Cspell:ignore gimsu igmus yusmig ysumgi zyxabc Ωmega Δelta */
22

33
import { createRuleTester } from 'eslint-vitest-rule-tester'
44
import typescriptParser from '@typescript-eslint/parser'
@@ -891,6 +891,51 @@ describe('sort-regexp', () => {
891891
})
892892
})
893893

894+
it('sorts alternatives inside single group without affecting backreference', async () => {
895+
await invalid({
896+
errors: [
897+
{
898+
data: { right: 'cat', left: 'dog' },
899+
messageId: 'unexpectedRegExpOrder',
900+
},
901+
],
902+
output: dedent(String.raw`
903+
/(cat|dog)\s\1/
904+
`),
905+
code: dedent(String.raw`
906+
/(dog|cat)\s\1/
907+
`),
908+
options: [options],
909+
})
910+
})
911+
912+
it('does not sort when multiple groups exist with backreferences', async () => {
913+
await valid({
914+
code: dedent(String.raw`
915+
/(c)(b)(a)\1\2\3/
916+
`),
917+
options: [options],
918+
})
919+
})
920+
921+
it('sorts alternatives with named group backreferences', async () => {
922+
await invalid({
923+
errors: [
924+
{
925+
data: { right: 'pet: cat', left: 'pet: dog' },
926+
messageId: 'unexpectedRegExpOrder',
927+
},
928+
],
929+
output: dedent(String.raw`
930+
/(?<pet>cat|dog)\s\k<pet>/
931+
`),
932+
code: dedent(String.raw`
933+
/(?<pet>dog|cat)\s\k<pet>/
934+
`),
935+
options: [options],
936+
})
937+
})
938+
894939
it('sorts alternatives with non-capturing groups', async () => {
895940
await invalid({
896941
errors: [
@@ -1280,6 +1325,42 @@ describe('sort-regexp', () => {
12801325
options: [options],
12811326
})
12821327
})
1328+
1329+
it('does not sort character classes with v flag (set operations)', async () => {
1330+
await valid({
1331+
code: dedent(String.raw`
1332+
/[za]/v
1333+
`),
1334+
options: [options],
1335+
})
1336+
})
1337+
1338+
it('does not sort character classes with v flag to avoid breaking set operations', async () => {
1339+
await valid({
1340+
code: dedent`
1341+
/[zyxabc]/v
1342+
`,
1343+
options: [options],
1344+
})
1345+
})
1346+
1347+
it('still sorts flags even with v flag present', async () => {
1348+
await invalid({
1349+
errors: [
1350+
{
1351+
messageId: 'unexpectedRegExpOrder',
1352+
data: { right: 'g', left: 'v' },
1353+
},
1354+
],
1355+
output: dedent`
1356+
/pattern/gv
1357+
`,
1358+
code: dedent`
1359+
/pattern/vg
1360+
`,
1361+
options: [options],
1362+
})
1363+
})
12831364
})
12841365

12851366
describe('natural', () => {
@@ -2551,6 +2632,42 @@ describe('sort-regexp', () => {
25512632
options: [options],
25522633
})
25532634
})
2635+
2636+
it('does not sort character classes with v flag (set operations)', async () => {
2637+
await valid({
2638+
code: dedent(String.raw`
2639+
/[za]/v
2640+
`),
2641+
options: [options],
2642+
})
2643+
})
2644+
2645+
it('does not sort character classes with v flag to avoid breaking set operations', async () => {
2646+
await valid({
2647+
code: dedent`
2648+
/[zyxabc]/v
2649+
`,
2650+
options: [options],
2651+
})
2652+
})
2653+
2654+
it('still sorts flags even with v flag present', async () => {
2655+
await invalid({
2656+
errors: [
2657+
{
2658+
messageId: 'unexpectedRegExpOrder',
2659+
data: { right: 'g', left: 'v' },
2660+
},
2661+
],
2662+
output: dedent`
2663+
/pattern/gv
2664+
`,
2665+
code: dedent`
2666+
/pattern/vg
2667+
`,
2668+
options: [options],
2669+
})
2670+
})
25542671
})
25552672

25562673
describe('line-length', () => {
@@ -2898,6 +3015,24 @@ describe('sort-regexp', () => {
28983015
options: [options],
28993016
})
29003017
})
3018+
3019+
it('does not sort character classes with v flag (set operations)', async () => {
3020+
await valid({
3021+
code: dedent(String.raw`
3022+
/[za]/v
3023+
`),
3024+
options: [options],
3025+
})
3026+
})
3027+
3028+
it('does not sort character classes with v flag to avoid breaking set operations', async () => {
3029+
await valid({
3030+
code: dedent`
3031+
/[zyxabc]/v
3032+
`,
3033+
options: [options],
3034+
})
3035+
})
29013036
})
29023037

29033038
describe('custom', () => {

0 commit comments

Comments
 (0)