@@ -1988,6 +1988,7 @@ export class AstFilterParser {
1988
1988
if ( parentEnd === parentBeg ) { return 0 ; }
1989
1989
const s = this . getNodeString ( parent ) ;
1990
1990
const optionsEnd = s . length ;
1991
+ const parseDetails = { node : 0 , len : 0 } ;
1991
1992
const head = this . allocHeadNode ( ) ;
1992
1993
let prev = head , next = 0 ;
1993
1994
let optionBeg = 0 , optionEnd = 0 ;
@@ -1997,11 +1998,11 @@ export class AstFilterParser {
1997
1998
parentBeg + optionBeg ,
1998
1999
parentBeg + optionsEnd // open ended
1999
2000
) ;
2000
- const { node : down , len : optionLen } = this . parseNetOption ( next ) ;
2001
+ this . parseNetOption ( next , parseDetails ) ;
2001
2002
// set next's end to down's end
2002
- optionEnd += optionLen ;
2003
+ optionEnd += parseDetails . len ;
2003
2004
this . nodes [ next + NODE_END_INDEX ] = parentBeg + optionEnd ;
2004
- this . linkDown ( next , down ) ;
2005
+ this . linkDown ( next , parseDetails . node ) ;
2005
2006
prev = this . linkRight ( prev , next ) ;
2006
2007
if ( optionEnd === optionsEnd ) { break ; }
2007
2008
optionBeg = optionEnd + 1 ;
@@ -2010,7 +2011,7 @@ export class AstFilterParser {
2010
2011
parentBeg + optionEnd ,
2011
2012
parentBeg + optionBeg
2012
2013
) ;
2013
- if ( optionLen === 0 || optionBeg === optionsEnd ) {
2014
+ if ( parseDetails . len === 0 || optionBeg === optionsEnd ) {
2014
2015
this . addNodeFlags ( next , NODE_FLAG_ERROR ) ;
2015
2016
this . addFlags ( AST_FLAG_HAS_ERROR ) ;
2016
2017
}
@@ -2023,15 +2024,17 @@ export class AstFilterParser {
2023
2024
return this . throwHeadNode ( head ) ;
2024
2025
}
2025
2026
2026
- parseNetOption ( parent ) {
2027
+ parseNetOption ( parent , parseDetails ) {
2027
2028
const parentBeg = this . nodes [ parent + NODE_BEG_INDEX ] ;
2028
2029
const s = this . getNodeString ( parent ) ;
2029
2030
const match = this . reNetOption . exec ( s ) || [ ] ;
2030
2031
if ( match . length === 0 ) {
2031
2032
this . addNodeFlags ( parent , NODE_FLAG_ERROR ) ;
2032
2033
this . addFlags ( AST_FLAG_HAS_ERROR ) ;
2033
2034
this . astError = AST_ERROR_OPTION_UNKNOWN ;
2034
- return { node : 0 , len : s . length } ;
2035
+ parseDetails . node = 0 ;
2036
+ parseDetails . len = s . length ;
2037
+ return ;
2035
2038
}
2036
2039
const head = this . allocHeadNode ( ) ;
2037
2040
let prev = head , next = 0 ;
@@ -2073,7 +2076,9 @@ export class AstFilterParser {
2073
2076
}
2074
2077
prev = this . linkRight ( prev , next ) ;
2075
2078
if ( assigned === false ) {
2076
- return { node : this . throwHeadNode ( head ) , len : matchEnd } ;
2079
+ parseDetails . node = this . throwHeadNode ( head ) ;
2080
+ parseDetails . len = matchEnd ;
2081
+ return ;
2077
2082
}
2078
2083
next = this . allocTypedNode (
2079
2084
NODE_TYPE_NET_OPTION_ASSIGN ,
@@ -2129,7 +2134,8 @@ export class AstFilterParser {
2129
2134
) ;
2130
2135
this . linkRight ( prev , next ) ;
2131
2136
}
2132
- return { node : this . throwHeadNode ( head ) , len : details . quoteEnd } ;
2137
+ parseDetails . node = this . throwHeadNode ( head ) ;
2138
+ parseDetails . len = details . quoteEnd ;
2133
2139
}
2134
2140
2135
2141
endOfNetOption ( s , beg ) {
@@ -2156,32 +2162,26 @@ export class AstFilterParser {
2156
2162
) ;
2157
2163
if ( parentEnd === parentBeg ) { return containerNode ; }
2158
2164
const separatorCode = separator . charCodeAt ( 0 ) ;
2165
+ const parseDetails = { separator, mode, node : 0 , len : 0 } ;
2159
2166
const listNode = this . allocHeadNode ( ) ;
2160
2167
let prev = listNode ;
2161
2168
let domainNode = 0 ;
2162
2169
let separatorNode = 0 ;
2163
2170
const s = this . getNodeString ( parent ) ;
2164
2171
const listEnd = s . length ;
2165
- let beg = 0 , end = 0 , c = 0 ;
2172
+ let beg = 0 , end = 0 ;
2166
2173
while ( beg < listEnd ) {
2167
- c = s . charCodeAt ( beg ) ;
2168
- if ( c === 0x7E /* ~ */ ) {
2169
- c = s . charCodeAt ( beg + 1 ) || 0 ;
2170
- }
2171
- if ( c !== 0x2F /* / */ ) {
2172
- end = s . indexOf ( separator , beg ) ;
2173
- } else {
2174
- end = s . indexOf ( '/' , beg + 1 ) ;
2175
- end = s . indexOf ( separator , end !== - 1 ? end + 1 : beg ) ;
2176
- }
2177
- if ( end === - 1 ) { end = listEnd ; }
2174
+ const next = this . allocTypedNode (
2175
+ NODE_TYPE_OPTION_VALUE_DOMAIN_RAW ,
2176
+ parentBeg + beg ,
2177
+ parentBeg + listEnd // open ended
2178
+ ) ;
2179
+ this . parseDomain ( next , parseDetails ) ;
2180
+ end = beg + parseDetails . len ;
2181
+ this . nodes [ next + NODE_END_INDEX ] = parentBeg + end ;
2178
2182
if ( end !== beg ) {
2179
- domainNode = this . allocTypedNode (
2180
- NODE_TYPE_OPTION_VALUE_DOMAIN_RAW ,
2181
- parentBeg + beg ,
2182
- parentBeg + end
2183
- ) ;
2184
- this . linkDown ( domainNode , this . parseDomain ( domainNode , mode ) ) ;
2183
+ domainNode = next ;
2184
+ this . linkDown ( domainNode , parseDetails . node ) ;
2185
2185
prev = this . linkRight ( prev , domainNode ) ;
2186
2186
} else {
2187
2187
domainNode = 0 ;
@@ -2217,23 +2217,38 @@ export class AstFilterParser {
2217
2217
return containerNode ;
2218
2218
}
2219
2219
2220
- parseDomain ( parent , mode = 0b0000 ) {
2220
+ parseDomain ( parent , parseDetails ) {
2221
2221
const parentBeg = this . nodes [ parent + NODE_BEG_INDEX ] ;
2222
2222
const parentEnd = this . nodes [ parent + NODE_END_INDEX ] ;
2223
+ const not = this . charCodeAt ( parentBeg ) === 0x7E /* ~ */ ;
2223
2224
let head = 0 , next = 0 ;
2224
2225
let beg = parentBeg ;
2225
- const c = this . charCodeAt ( beg ) ;
2226
- if ( c === 0x7E /* ~ */ ) {
2226
+ if ( not ) {
2227
2227
this . addNodeFlags ( parent , NODE_FLAG_IS_NEGATED ) ;
2228
2228
head = this . allocTypedNode ( NODE_TYPE_OPTION_VALUE_NOT , beg , beg + 1 ) ;
2229
- if ( ( mode & 0b1000 ) === 0 ) {
2229
+ if ( ( parseDetails . mode & 0b1000 ) === 0 ) {
2230
2230
this . addNodeFlags ( parent , NODE_FLAG_ERROR ) ;
2231
2231
}
2232
2232
beg += 1 ;
2233
2233
}
2234
- if ( beg !== parentEnd ) {
2235
- next = this . allocTypedNode ( NODE_TYPE_OPTION_VALUE_DOMAIN , beg , parentEnd ) ;
2236
- const hn = this . normalizeDomainValue ( this . getNodeString ( next ) , mode ) ;
2234
+ const c0 = this . charCodeAt ( beg ) ;
2235
+ let end = beg ;
2236
+ let type = 0 ;
2237
+ if ( c0 === 0x2F /* / */ ) {
2238
+ end = this . indexOf ( '/' , beg + 1 , parentEnd ) ;
2239
+ if ( end !== - 1 ) { end += 1 ; }
2240
+ type = 1 ;
2241
+ } else if ( c0 === 0x5B /* [ */ && this . startsWith ( '[$domain=/' , beg ) ) {
2242
+ end = this . indexOf ( '/]' , beg + 10 , parentEnd ) ;
2243
+ if ( end !== - 1 ) { end += 2 ; }
2244
+ type = 2 ;
2245
+ } else {
2246
+ end = this . indexOf ( parseDetails . separator , end , parentEnd ) ;
2247
+ }
2248
+ if ( end === - 1 ) { end = parentEnd ; }
2249
+ if ( beg !== end ) {
2250
+ next = this . allocTypedNode ( NODE_TYPE_OPTION_VALUE_DOMAIN , beg , end ) ;
2251
+ const hn = this . normalizeDomainValue ( next , type , parseDetails . mode ) ;
2237
2252
if ( hn !== undefined ) {
2238
2253
if ( hn !== '' ) {
2239
2254
this . setNodeTransform ( next , hn ) ;
@@ -2252,7 +2267,8 @@ export class AstFilterParser {
2252
2267
this . addNodeFlags ( parent , NODE_FLAG_ERROR ) ;
2253
2268
this . addFlags ( AST_FLAG_HAS_ERROR ) ;
2254
2269
}
2255
- return head ;
2270
+ parseDetails . node = head ;
2271
+ parseDetails . len = end - parentBeg ;
2256
2272
}
2257
2273
2258
2274
// mode bits:
@@ -2261,16 +2277,16 @@ export class AstFilterParser {
2261
2277
// 0b00100: can use single wildcard
2262
2278
// 0b01000: can be negated
2263
2279
// 0b10000: can be a regex
2264
- normalizeDomainValue ( s , modeBits ) {
2265
- if ( ( modeBits & 0b10000 ) === 0 ||
2266
- s . length <= 2 ||
2267
- s . charCodeAt ( 0 ) !== 0x2F /* / */ ||
2268
- exCharCodeAt ( s , - 1 ) !== 0x2F /* / */
2269
- ) {
2280
+ normalizeDomainValue ( node , type , modeBits ) {
2281
+ const s = this . getNodeString ( node ) ;
2282
+ if ( type === 0 ) {
2270
2283
return this . normalizeHostnameValue ( s , modeBits ) ;
2271
2284
}
2272
- const source = this . normalizeRegexPattern ( s ) ;
2285
+ if ( ( modeBits & 0b10000 ) === 0 ) { return '' ; }
2286
+ const regex = type === 1 ? s : `/${ s . slice ( 10 , - 2 ) } /` ;
2287
+ const source = this . normalizeRegexPattern ( regex ) ;
2273
2288
if ( source === '' ) { return '' ; }
2289
+ if ( type === 1 && source === regex ) { return ; }
2274
2290
return `/${ source } /` ;
2275
2291
}
2276
2292
@@ -2857,6 +2873,15 @@ export class AstFilterParser {
2857
2873
return pos < this . rawEnd ? this . raw . charCodeAt ( pos ) : - 1 ;
2858
2874
}
2859
2875
2876
+ indexOf ( needle , beg , end = 0 ) {
2877
+ const haystack = end === 0 ? this . raw : this . raw . slice ( 0 , end ) ;
2878
+ return haystack . indexOf ( needle , beg ) ;
2879
+ }
2880
+
2881
+ startsWith ( s , pos ) {
2882
+ return pos < this . rawEnd && this . raw . startsWith ( s , pos ) ;
2883
+ }
2884
+
2860
2885
isTokenCharCode ( c ) {
2861
2886
return c === 0x25 ||
2862
2887
c >= 0x30 && c <= 0x39 ||
0 commit comments