11import type { EncodeResult } from '../encoder/types' ;
22import type { RegexConstruct } from '../types' ;
33
4- export interface CharacterClass extends RegexConstruct {
5- type : 'characterClass' ;
6- escape ?: string ;
7- chars : string [ ] ;
8- ranges : CharacterRange [ ] ;
9- isNegated : boolean ;
10- encode : ( ) => EncodeResult ;
11- }
12-
134/**
145 * Character range from start to end (inclusive).
156 */
@@ -18,6 +9,14 @@ export interface CharacterRange {
189 end : string ;
1910}
2011
12+ export interface CharacterClass extends RegexConstruct {
13+ type : 'characterClass' ;
14+ escape ?: string ;
15+ chars ?: string [ ] ;
16+ ranges ?: CharacterRange [ ] ;
17+ isNegated ?: boolean ;
18+ }
19+
2120/**
2221 * Matches any single character.
2322 * Cannot be used as a part of character class.
@@ -30,54 +29,36 @@ export const any: EncodeResult = {
3029export const digit : CharacterClass = {
3130 type : 'characterClass' ,
3231 escape : '\\d' ,
33- chars : [ ] ,
34- ranges : [ ] ,
35- isNegated : false ,
3632 encode : encodeCharacterClass ,
3733} ;
3834
3935export const nonDigit : CharacterClass = {
4036 type : 'characterClass' ,
4137 escape : '\\D' ,
42- chars : [ ] ,
43- ranges : [ ] ,
44- isNegated : false ,
4538 encode : encodeCharacterClass ,
4639} ;
4740
4841export const word : CharacterClass = {
4942 type : 'characterClass' ,
5043 escape : '\\w' ,
51- chars : [ ] ,
52- ranges : [ ] ,
53- isNegated : false ,
5444 encode : encodeCharacterClass ,
5545} ;
5646
5747export const nonWord : CharacterClass = {
5848 type : 'characterClass' ,
5949 escape : '\\W' ,
60- chars : [ ] ,
61- ranges : [ ] ,
62- isNegated : false ,
6350 encode : encodeCharacterClass ,
6451} ;
6552
6653export const whitespace : CharacterClass = {
6754 type : 'characterClass' ,
6855 escape : '\\s' ,
69- chars : [ ] ,
70- ranges : [ ] ,
71- isNegated : false ,
7256 encode : encodeCharacterClass ,
7357} ;
7458
7559export const nonWhitespace : CharacterClass = {
7660 type : 'characterClass' ,
7761 escape : '\\S' ,
78- chars : [ ] ,
79- ranges : [ ] ,
80- isNegated : false ,
8162 encode : encodeCharacterClass ,
8263} ;
8364
@@ -107,9 +88,8 @@ export function charClass(...elements: CharacterClass[]): CharacterClass {
10788
10889 return {
10990 type : 'characterClass' ,
110- chars : elements . map ( ( c ) => getAllChars ( c ) ) . flat ( ) ,
111- ranges : elements . map ( ( c ) => c . ranges ) . flat ( ) ,
112- isNegated : false ,
91+ chars : elements . map ( ( c ) => getAllChars ( c ) ?? [ ] ) . flat ( ) ,
92+ ranges : elements . map ( ( c ) => c . ranges ?? [ ] ) . flat ( ) ,
11393 encode : encodeCharacterClass ,
11494 } ;
11595}
@@ -129,9 +109,7 @@ export function charRange(start: string, end: string): CharacterClass {
129109
130110 return {
131111 type : 'characterClass' ,
132- chars : [ ] ,
133112 ranges : [ { start, end } ] ,
134- isNegated : false ,
135113 encode : encodeCharacterClass ,
136114 } ;
137115}
@@ -146,15 +124,14 @@ export function anyOf(characters: string): CharacterClass {
146124 return {
147125 type : 'characterClass' ,
148126 chars,
149- ranges : [ ] ,
150- isNegated : false ,
151127 encode : encodeCharacterClass ,
152128 } ;
153129}
154130
155131export function negated ( element : CharacterClass ) : CharacterClass {
156132 return {
157133 type : 'characterClass' ,
134+ escape : element . escape ,
158135 chars : element . chars ,
159136 ranges : element . ranges ,
160137 isNegated : ! element . isNegated ,
@@ -168,27 +145,27 @@ export function negated(element: CharacterClass): CharacterClass {
168145export const inverted = negated ;
169146
170147function encodeCharacterClass ( this : CharacterClass ) : EncodeResult {
171- if ( this . escape === undefined && this . chars . length === 0 && this . ranges . length === 0 ) {
148+ if ( this . escape === undefined && ! this . chars ? .length && ! this . ranges ? .length ) {
172149 throw new Error ( 'Character class should contain at least one character or character range' ) ;
173150 }
174151
175- // Direct rendering for single-character class
176- if ( this . escape !== undefined && ! this . chars . length && ! this . ranges . length && ! this . isNegated ) {
152+ // Direct rendering for escapes
153+ if ( this . escape !== undefined && ! this . chars ? .length && ! this . ranges ? .length && ! this . isNegated ) {
177154 return {
178155 precedence : 'atom' ,
179156 pattern : this . escape ,
180157 } ;
181158 }
182159
183- const allChars = getAllChars ( this ) ;
160+ const allChars = getAllChars ( this ) ?? [ ] ;
184161
185162 // If passed characters includes hyphen (`-`) it need to be moved to
186163 // first (or last) place in order to treat it as hyphen character and not a range.
187164 // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes#types
188165 const hyphen = allChars . includes ( '-' ) ? '-' : '' ;
189166 const caret = allChars . includes ( '^' ) ? '^' : '' ;
190167 const otherChars = allChars . filter ( ( c ) => c !== '-' && c !== '^' ) . join ( '' ) ;
191- const ranges = this . ranges . map ( ( { start, end } ) => `${ start } -${ end } ` ) . join ( '' ) ;
168+ const ranges = this . ranges ? .map ( ( { start, end } ) => `${ start } -${ end } ` ) . join ( '' ) ?? '' ;
192169 const negation = this . isNegated ? '^' : '' ;
193170
194171 let pattern = `[${ negation } ${ ranges } ${ otherChars } ${ caret } ${ hyphen } ]` ;
@@ -209,5 +186,5 @@ function getAllChars(characterClass: CharacterClass) {
209186 return characterClass . chars ;
210187 }
211188
212- return [ characterClass . escape , ...characterClass . chars ] ;
189+ return [ characterClass . escape , ...( characterClass . chars ?? [ ] ) ] ;
213190}
0 commit comments