Skip to content

Commit 9c57fa2

Browse files
authoredApr 30, 2024··
refactor: cleanup char class (#87)
1 parent de06af1 commit 9c57fa2

File tree

1 file changed

+17
-40
lines changed

1 file changed

+17
-40
lines changed
 

‎src/constructs/character-class.ts

+17-40
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
import type { EncodeResult } from '../encoder/types';
22
import 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 = {
3029
export const digit: CharacterClass = {
3130
type: 'characterClass',
3231
escape: '\\d',
33-
chars: [],
34-
ranges: [],
35-
isNegated: false,
3632
encode: encodeCharacterClass,
3733
};
3834

3935
export const nonDigit: CharacterClass = {
4036
type: 'characterClass',
4137
escape: '\\D',
42-
chars: [],
43-
ranges: [],
44-
isNegated: false,
4538
encode: encodeCharacterClass,
4639
};
4740

4841
export const word: CharacterClass = {
4942
type: 'characterClass',
5043
escape: '\\w',
51-
chars: [],
52-
ranges: [],
53-
isNegated: false,
5444
encode: encodeCharacterClass,
5545
};
5646

5747
export const nonWord: CharacterClass = {
5848
type: 'characterClass',
5949
escape: '\\W',
60-
chars: [],
61-
ranges: [],
62-
isNegated: false,
6350
encode: encodeCharacterClass,
6451
};
6552

6653
export const whitespace: CharacterClass = {
6754
type: 'characterClass',
6855
escape: '\\s',
69-
chars: [],
70-
ranges: [],
71-
isNegated: false,
7256
encode: encodeCharacterClass,
7357
};
7458

7559
export 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

155131
export 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 {
168145
export const inverted = negated;
169146

170147
function 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

Comments
 (0)
Please sign in to comment.