1
1
// Following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
2
2
3
- // [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?
4
- const RE_NTH_ELEMENT = / ^ ( [ + - ] ? \d * n ) ? \s * (?: ( [ + - ] ? ) \s * ( \d + ) ) ? $ / ;
3
+ // Whitespace as per https://www.w3.org/TR/selectors-3/#lex is " \t\r\n\f"
4
+ const whitespace = new Set ( [ 9 , 10 , 12 , 13 , 32 ] ) ;
5
+ const ZERO = "0" . charCodeAt ( 0 ) ;
6
+ const NINE = "9" . charCodeAt ( 0 ) ;
5
7
6
8
/**
7
9
* Parses an expression.
@@ -19,24 +21,72 @@ export function parse(formula: string): [a: number, b: number] {
19
21
return [ 2 , 1 ] ;
20
22
}
21
23
22
- const parsed = formula . match ( RE_NTH_ELEMENT ) ;
24
+ // Parse [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?
23
25
24
- if ( ! parsed ) {
26
+ let idx = 0 ;
27
+
28
+ let a = 0 ;
29
+ let sign = readSign ( ) ;
30
+ let number = readNumber ( ) ;
31
+
32
+ if ( idx < formula . length && formula . charAt ( idx ) === "n" ) {
33
+ idx ++ ;
34
+ a = sign * ( number ?? 1 ) ;
35
+
36
+ skipWhitespace ( ) ;
37
+
38
+ if ( idx < formula . length ) {
39
+ sign = readSign ( ) ;
40
+ skipWhitespace ( ) ;
41
+ number = readNumber ( ) ;
42
+ } else {
43
+ sign = number = 0 ;
44
+ }
45
+ }
46
+
47
+ // Throw if there is anything else
48
+ if ( number === null || idx < formula . length ) {
25
49
throw new Error ( `n-th rule couldn't be parsed ('${ formula } ')` ) ;
26
50
}
27
51
28
- let a ;
52
+ return [ a , sign * number ] ;
29
53
30
- if ( parsed [ 1 ] ) {
31
- a = parseInt ( parsed [ 1 ] , 10 ) ;
32
- if ( isNaN ( a ) ) {
33
- a = parsed [ 1 ] . startsWith ( "-" ) ? - 1 : 1 ;
54
+ function readSign ( ) {
55
+ if ( formula . charAt ( idx ) === "-" ) {
56
+ idx ++ ;
57
+ return - 1 ;
34
58
}
35
- } else a = 0 ;
36
59
37
- const b =
38
- ( parsed [ 2 ] === "-" ? - 1 : 1 ) *
39
- ( parsed [ 3 ] ? parseInt ( parsed [ 3 ] , 10 ) : 0 ) ;
60
+ if ( formula . charAt ( idx ) === "+" ) {
61
+ idx ++ ;
62
+ }
40
63
41
- return [ a , b ] ;
64
+ return 1 ;
65
+ }
66
+
67
+ function readNumber ( ) {
68
+ const start = idx ;
69
+ let value = 0 ;
70
+
71
+ while (
72
+ idx < formula . length &&
73
+ formula . charCodeAt ( idx ) >= ZERO &&
74
+ formula . charCodeAt ( idx ) <= NINE
75
+ ) {
76
+ value = value * 10 + ( formula . charCodeAt ( idx ) - ZERO ) ;
77
+ idx ++ ;
78
+ }
79
+
80
+ // Return `null` if we didn't read anything.
81
+ return idx === start ? null : value ;
82
+ }
83
+
84
+ function skipWhitespace ( ) {
85
+ while (
86
+ idx < formula . length &&
87
+ whitespace . has ( formula . charCodeAt ( idx ) )
88
+ ) {
89
+ idx ++ ;
90
+ }
91
+ }
42
92
}
3 commit comments
Cas154 commentedon Dec 13, 2022
work
Mtillmann commentedon Sep 1, 2023
does this fix the regexp complexity issue? if so - can we get a new release? thanks
Mtillmann commentedon Sep 1, 2023
nevermind, I have some outdated third party dependency