@@ -8,8 +8,12 @@ import type {
8
8
LookaroundAssertion ,
9
9
} from "@eslint-community/regexpp/ast"
10
10
import { isEqualNodes } from "./is-equals"
11
- import type { ReadonlyFlags , ToCharSetElement } from "regexp-ast-analysis"
12
- import { toCharSet } from "regexp-ast-analysis"
11
+ import type {
12
+ ReadonlyFlags ,
13
+ ToCharSetElement ,
14
+ ToUnicodeSetElement ,
15
+ } from "regexp-ast-analysis"
16
+ import { toCharSet , toUnicodeSet } from "regexp-ast-analysis"
13
17
import type { CharSet } from "refa"
14
18
15
19
type Options = {
@@ -54,6 +58,10 @@ class NormalizedCharacter implements NormalizedNodeBase {
54
58
return new NormalizedCharacter ( toCharSet ( element , options . flags ) )
55
59
}
56
60
61
+ public static fromChars ( charSet : CharSet ) {
62
+ return new NormalizedCharacter ( charSet )
63
+ }
64
+
57
65
private constructor ( charSet : CharSet ) {
58
66
this . charSet = charSet
59
67
}
@@ -69,7 +77,7 @@ class NormalizedAlternative implements NormalizedNodeBase {
69
77
70
78
public readonly raw : string
71
79
72
- public readonly elements : NormalizedNode [ ]
80
+ public readonly elements : readonly NormalizedNode [ ]
73
81
74
82
public static fromAlternative ( node : Alternative , options : Options ) {
75
83
const normalizeElements = [
@@ -107,7 +115,7 @@ class NormalizedAlternative implements NormalizedNodeBase {
107
115
108
116
public static fromElements (
109
117
elements : NormalizedNode [ ] ,
110
- node : Alternative | Quantifier ,
118
+ node : Alternative | Quantifier | ToUnicodeSetElement ,
111
119
) {
112
120
const normalizeElements = [
113
121
...NormalizedAlternative . normalizedElements ( function * ( ) {
@@ -131,7 +139,7 @@ class NormalizedAlternative implements NormalizedNodeBase {
131
139
132
140
private constructor (
133
141
elements : NormalizedNode [ ] ,
134
- node : Alternative | Quantifier ,
142
+ node : Alternative | Quantifier | ToUnicodeSetElement ,
135
143
) {
136
144
this . raw = node . raw
137
145
this . elements = elements
@@ -148,11 +156,9 @@ class NormalizedDisjunctions implements NormalizedNodeBase {
148
156
149
157
public readonly raw : string
150
158
151
- public readonly node : CapturingGroup | Group | Pattern
159
+ private readonly getAlternatives : ( ) => readonly NormalizedAlternative [ ]
152
160
153
- private readonly options : Options
154
-
155
- public normalizedAlternatives ?: NormalizedAlternative [ ]
161
+ private normalizedAlternatives ?: readonly NormalizedAlternative [ ]
156
162
157
163
public static fromNode (
158
164
node : CapturingGroup | Group | Pattern ,
@@ -164,32 +170,35 @@ class NormalizedDisjunctions implements NormalizedNodeBase {
164
170
options ,
165
171
)
166
172
}
167
- return new NormalizedDisjunctions ( node , options )
173
+ return new NormalizedDisjunctions ( node , ( ) => {
174
+ return node . alternatives . map ( ( alt ) => {
175
+ const n = normalizeNode ( alt , options )
176
+ if ( n . type === "NormalizedAlternative" ) {
177
+ return n
178
+ }
179
+ return NormalizedAlternative . fromElements ( [ n ] , alt )
180
+ } )
181
+ } )
182
+ }
183
+
184
+ public static fromAlternatives (
185
+ alternatives : readonly NormalizedAlternative [ ] ,
186
+ node : CapturingGroup | Group | Pattern | ToUnicodeSetElement ,
187
+ ) {
188
+ return new NormalizedDisjunctions ( node , ( ) => alternatives )
168
189
}
169
190
170
191
private constructor (
171
- node : CapturingGroup | Group | Pattern ,
172
- options : Options ,
192
+ node : CapturingGroup | Group | Pattern | ToUnicodeSetElement ,
193
+ getAlternatives : ( ) => readonly NormalizedAlternative [ ] ,
173
194
) {
174
195
this . raw = node . raw
175
- this . node = node
176
- this . options = options
196
+ this . getAlternatives = getAlternatives
177
197
}
178
198
179
- public get alternatives ( ) {
180
- if ( this . normalizedAlternatives ) {
181
- return this . normalizedAlternatives
182
- }
183
- this . normalizedAlternatives = [ ]
184
- for ( const alt of this . node . alternatives ) {
185
- const node = normalizeNode ( alt , this . options )
186
- if ( node . type === "NormalizedAlternative" ) {
187
- this . normalizedAlternatives . push ( node )
188
- } else {
189
- this . normalizedAlternatives . push (
190
- NormalizedAlternative . fromElements ( [ node ] , alt ) ,
191
- )
192
- }
199
+ public get alternatives ( ) : readonly NormalizedAlternative [ ] {
200
+ if ( ! this . normalizedAlternatives ) {
201
+ this . normalizedAlternatives = this . getAlternatives ( )
193
202
}
194
203
return this . normalizedAlternatives
195
204
}
@@ -208,7 +217,7 @@ class NormalizedLookaroundAssertion implements NormalizedNodeBase {
208
217
209
218
private readonly options : Options
210
219
211
- public normalizedAlternatives ?: NormalizedAlternative [ ]
220
+ private normalizedAlternatives ?: NormalizedAlternative [ ]
212
221
213
222
public static fromNode ( node : LookaroundAssertion , options : Options ) {
214
223
return new NormalizedLookaroundAssertion ( node , options )
@@ -220,7 +229,7 @@ class NormalizedLookaroundAssertion implements NormalizedNodeBase {
220
229
this . options = options
221
230
}
222
231
223
- public get alternatives ( ) {
232
+ public get alternatives ( ) : readonly NormalizedAlternative [ ] {
224
233
if ( this . normalizedAlternatives ) {
225
234
return this . normalizedAlternatives
226
235
}
@@ -425,44 +434,66 @@ function normalizeNodeWithoutCache(
425
434
node : Node ,
426
435
options : Options ,
427
436
) : NormalizedNode {
428
- if (
429
- node . type === "CharacterSet" ||
430
- node . type === "CharacterClass" ||
431
- node . type === "Character" ||
432
- node . type === "CharacterClassRange"
433
- ) {
434
- // FIXME: TS Error
435
- // @ts -expect-error -- FIXME
436
- return NormalizedCharacter . fromElement ( node , options )
437
- }
438
- if ( node . type === "Alternative" ) {
439
- return NormalizedAlternative . fromAlternative ( node , options )
440
- }
441
- if ( node . type === "Quantifier" ) {
442
- return NormalizedOptional . fromQuantifier ( node , options )
443
- }
444
- if (
445
- node . type === "CapturingGroup" ||
446
- node . type === "Group" ||
447
- node . type === "Pattern"
448
- ) {
449
- return NormalizedDisjunctions . fromNode ( node , options )
450
- }
451
- if ( node . type === "RegExpLiteral" ) {
452
- return normalizeNode ( node . pattern , options )
453
- }
454
- if ( node . type === "Assertion" ) {
455
- if ( node . kind === "lookahead" || node . kind === "lookbehind" ) {
456
- return NormalizedLookaroundAssertion . fromNode ( node , options )
437
+ switch ( node . type ) {
438
+ case "CharacterSet" :
439
+ case "CharacterClass" :
440
+ case "Character" :
441
+ case "CharacterClassRange" :
442
+ case "ExpressionCharacterClass" :
443
+ case "ClassIntersection" :
444
+ case "ClassSubtraction" :
445
+ case "ClassStringDisjunction" :
446
+ case "StringAlternative" : {
447
+ const set = toUnicodeSet ( node , options . flags )
448
+ if ( set . accept . isEmpty ) {
449
+ return NormalizedCharacter . fromChars ( set . chars )
450
+ }
451
+
452
+ const alternatives = set . wordSets . map ( ( wordSet ) => {
453
+ return NormalizedAlternative . fromElements (
454
+ wordSet . map ( NormalizedCharacter . fromChars ) ,
455
+ node ,
456
+ )
457
+ } )
458
+ return NormalizedDisjunctions . fromAlternatives ( alternatives , node )
457
459
}
458
- return NormalizedOther . fromNode ( node )
460
+
461
+ case "Alternative" :
462
+ return NormalizedAlternative . fromAlternative ( node , options )
463
+
464
+ case "Quantifier" :
465
+ return NormalizedOptional . fromQuantifier ( node , options )
466
+
467
+ case "CapturingGroup" :
468
+ case "Group" :
469
+ case "Pattern" :
470
+ return NormalizedDisjunctions . fromNode ( node , options )
471
+
472
+ case "Assertion" :
473
+ if ( node . kind === "lookahead" || node . kind === "lookbehind" ) {
474
+ return NormalizedLookaroundAssertion . fromNode ( node , options )
475
+ }
476
+ return NormalizedOther . fromNode ( node )
477
+
478
+ case "RegExpLiteral" :
479
+ return normalizeNode ( node . pattern , options )
480
+
481
+ case "Backreference" :
482
+ case "Flags" :
483
+ return NormalizedOther . fromNode ( node )
484
+
485
+ default :
486
+ return assertNever ( node )
459
487
}
460
- return NormalizedOther . fromNode ( node )
488
+ }
489
+
490
+ function assertNever ( value : never ) : never {
491
+ throw new Error ( `Invalid value: ${ value } ` )
461
492
}
462
493
463
494
/** Check whether the right node is covered by the left nodes. */
464
495
function isCoveredAnyNode (
465
- left : NormalizedNode [ ] ,
496
+ left : readonly NormalizedNode [ ] ,
466
497
right : NormalizedNode ,
467
498
options : Options ,
468
499
) {
@@ -476,8 +507,8 @@ function isCoveredAnyNode(
476
507
477
508
/** Check whether the right nodes is covered by the left nodes. */
478
509
function isCoveredAltNodes (
479
- leftNodes : NormalizedNode [ ] ,
480
- rightNodes : NormalizedNode [ ] ,
510
+ leftNodes : readonly NormalizedNode [ ] ,
511
+ rightNodes : readonly NormalizedNode [ ] ,
481
512
options : Options ,
482
513
) : boolean {
483
514
const left = options . canOmitRight ? omitEnds ( leftNodes ) : [ ...leftNodes ]
@@ -561,7 +592,7 @@ function isCoveredAltNodes(
561
592
/**
562
593
* Exclude the end optionals.
563
594
*/
564
- function omitEnds ( nodes : NormalizedNode [ ] ) : NormalizedNode [ ] {
595
+ function omitEnds ( nodes : readonly NormalizedNode [ ] ) : NormalizedNode [ ] {
565
596
for ( let index = nodes . length - 1 ; index >= 0 ; index -- ) {
566
597
const node = nodes [ index ]
567
598
if ( node . type !== "NormalizedOptional" ) {
0 commit comments