@@ -38,12 +38,12 @@ function deepTrieNodeToJSON(node: TrieNode,
38
38
39
39
const createNode = < Meta = any > ( allSubdomain = false , parent : TrieNode | null = null ) : TrieNode => [ false , allSubdomain , parent , new Map < string , TrieNode > ( ) , null ] as TrieNode < Meta > ;
40
40
41
- export function hostnameToTokens ( hostname : string ) : string [ ] {
41
+ export function hostnameToTokens ( hostname : string , hostnameFromIndex : number ) : string [ ] {
42
42
const tokens = hostname . split ( '.' ) ;
43
43
const results : string [ ] = [ ] ;
44
44
let token = '' ;
45
45
46
- for ( let i = 0 , l = tokens . length ; i < l ; i ++ ) {
46
+ for ( let i = hostnameFromIndex , l = tokens . length ; i < l ; i ++ ) {
47
47
token = tokens [ i ] ;
48
48
if ( token . length > 0 ) {
49
49
results . push ( token ) ;
@@ -53,15 +53,15 @@ export function hostnameToTokens(hostname: string): string[] {
53
53
return results ;
54
54
}
55
55
56
- function walkHostnameTokens ( hostname : string , onToken : ( token : string ) => boolean | null ) : boolean | null {
56
+ function walkHostnameTokens ( hostname : string , onToken : ( token : string ) => boolean | null , hostnameFromIndex : number ) : boolean | null {
57
57
const tokens = hostname . split ( '.' ) ;
58
58
59
59
const l = tokens . length - 1 ;
60
60
61
61
// we are at the first of hostname, no splitor there
62
62
let token = '' ;
63
63
64
- for ( let i = l ; i >= 0 ; i -- ) {
64
+ for ( let i = l ; i >= hostnameFromIndex ; i -- ) {
65
65
token = tokens [ i ] ;
66
66
if ( token . length > 0 ) {
67
67
const t = onToken ( token ) ;
@@ -104,7 +104,7 @@ abstract class Triebase<Meta = any> {
104
104
}
105
105
}
106
106
107
- public abstract add ( suffix : string , includeAllSubdomain ?: boolean , meta ?: Meta ) : void ;
107
+ public abstract add ( suffix : string , includeAllSubdomain ?: boolean , meta ?: Meta , hostnameFromIndex ?: number ) : void ;
108
108
109
109
protected walkIntoLeafWithTokens (
110
110
tokens : string [ ] ,
@@ -138,6 +138,7 @@ abstract class Triebase<Meta = any> {
138
138
139
139
protected walkIntoLeafWithSuffix (
140
140
suffix : string ,
141
+ hostnameFromIndex : number ,
141
142
onLoop : ( node : TrieNode , parent : TrieNode , token : string ) => void = noop
142
143
) {
143
144
let node : TrieNode = this . $root ;
@@ -161,18 +162,19 @@ abstract class Triebase<Meta = any> {
161
162
return false ;
162
163
} ;
163
164
164
- if ( walkHostnameTokens ( suffix , onToken ) === null ) {
165
+ if ( walkHostnameTokens ( suffix , onToken , hostnameFromIndex ) === null ) {
165
166
return null ;
166
167
}
167
168
168
169
return { node, parent } ;
169
170
} ;
170
171
171
172
public contains ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' ) : boolean {
173
+ let hostnameFromIndex = 0 ;
172
174
if ( suffix [ 0 ] === '.' ) {
173
- suffix = suffix . slice ( 1 ) ;
175
+ hostnameFromIndex = 1 ;
174
176
}
175
- const res = this . walkIntoLeafWithSuffix ( suffix ) ;
177
+ const res = this . walkIntoLeafWithSuffix ( suffix , hostnameFromIndex ) ;
176
178
if ( ! res ) return false ;
177
179
if ( includeAllSubdomain ) return res . node [ 1 ] ;
178
180
return true ;
@@ -330,14 +332,15 @@ abstract class Triebase<Meta = any> {
330
332
*/
331
333
public find (
332
334
inputSuffix : string ,
333
- subdomainOnly = inputSuffix [ 0 ] === '.'
335
+ subdomainOnly = inputSuffix [ 0 ] === '.' ,
336
+ hostnameFromIndex = 0
334
337
// /** @default true */ includeEqualWithSuffix = true
335
338
) : string [ ] {
336
339
if ( inputSuffix [ 0 ] === '.' ) {
337
- inputSuffix = inputSuffix . slice ( 1 ) ;
340
+ hostnameFromIndex = 1 ;
338
341
}
339
342
340
- const inputTokens = hostnameToTokens ( inputSuffix ) ;
343
+ const inputTokens = hostnameToTokens ( inputSuffix , hostnameFromIndex ) ;
341
344
const res = this . walkIntoLeafWithTokens ( inputTokens ) ;
342
345
if ( res === null ) return [ ] ;
343
346
@@ -346,7 +349,7 @@ abstract class Triebase<Meta = any> {
346
349
const onMatches = subdomainOnly
347
350
? ( suffix : string [ ] , subdomain : boolean ) => { // fast path (default option)
348
351
const d = fastStringArrayJoin ( suffix , '.' ) ;
349
- if ( ! subdomain && d === inputSuffix ) return ;
352
+ if ( ! subdomain && subStringEqual ( inputSuffix , d , 1 ) ) return ;
350
353
351
354
results . push ( subdomain ? '.' + d : d ) ;
352
355
}
@@ -368,7 +371,7 @@ abstract class Triebase<Meta = any> {
368
371
* Method used to delete a prefix from the trie.
369
372
*/
370
373
public remove ( suffix : string ) : boolean {
371
- const res = this . getSingleChildLeaf ( hostnameToTokens ( suffix ) ) ;
374
+ const res = this . getSingleChildLeaf ( hostnameToTokens ( suffix , 0 ) ) ;
372
375
if ( res === null ) return false ;
373
376
374
377
if ( ! res . node [ 0 ] ) return false ;
@@ -392,11 +395,13 @@ abstract class Triebase<Meta = any> {
392
395
* Method used to assert whether the given prefix exists in the Trie.
393
396
*/
394
397
public has ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' ) : boolean {
398
+ let hostnameFromIndex = 0 ;
399
+
395
400
if ( suffix [ 0 ] === '.' ) {
396
- suffix = suffix . slice ( 1 ) ;
401
+ hostnameFromIndex = 1 ;
397
402
}
398
403
399
- const res = this . walkIntoLeafWithSuffix ( suffix ) ;
404
+ const res = this . walkIntoLeafWithSuffix ( suffix , hostnameFromIndex ) ;
400
405
401
406
if ( res === null ) return false ;
402
407
if ( ! res . node [ 0 ] ) return false ;
@@ -485,12 +490,12 @@ abstract class Triebase<Meta = any> {
485
490
export class HostnameSmolTrie < Meta = any > extends Triebase < Meta > {
486
491
public smolTree = true ;
487
492
488
- add ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' , meta ?: Meta ) : void {
493
+ add ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' , meta ?: Meta , hostnameFromIndex = 0 ) : void {
489
494
let node : TrieNode < Meta > = this . $root ;
490
495
let curNodeChildren : Map < string , TrieNode < Meta > > = node [ 3 ] ;
491
496
492
- if ( suffix [ 0 ] === '.' ) {
493
- suffix = suffix . slice ( 1 ) ;
497
+ if ( hostnameFromIndex === 0 && suffix [ 0 ] === '.' ) {
498
+ hostnameFromIndex = 1 ;
494
499
}
495
500
496
501
const onToken = ( token : string ) => {
@@ -512,7 +517,7 @@ export class HostnameSmolTrie<Meta = any> extends Triebase<Meta> {
512
517
} ;
513
518
514
519
// When walkHostnameTokens returns true, we should skip the rest
515
- if ( walkHostnameTokens ( suffix , onToken ) ) {
520
+ if ( walkHostnameTokens ( suffix , onToken , hostnameFromIndex ) ) {
516
521
return ;
517
522
}
518
523
@@ -539,12 +544,12 @@ export class HostnameSmolTrie<Meta = any> extends Triebase<Meta> {
539
544
node [ 4 ] = meta ! ;
540
545
}
541
546
542
- public whitelist ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' ) {
547
+ public whitelist ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' , hostnameFromIndex = 0 ) {
543
548
if ( suffix [ 0 ] === '.' ) {
544
- suffix = suffix . slice ( 1 ) ;
549
+ hostnameFromIndex = 1 ;
545
550
}
546
551
547
- const tokens = hostnameToTokens ( suffix ) ;
552
+ const tokens = hostnameToTokens ( suffix , hostnameFromIndex ) ;
548
553
const res = this . getSingleChildLeaf ( tokens ) ;
549
554
550
555
if ( res === null ) return ;
@@ -579,7 +584,7 @@ export class HostnameTrie<Meta = any> extends Triebase<Meta> {
579
584
return this . $size ;
580
585
}
581
586
582
- add ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' , meta ?: Meta ) : void {
587
+ add ( suffix : string , includeAllSubdomain = suffix [ 0 ] === '.' , meta ?: Meta , hostnameFromIndex = 0 ) : void {
583
588
let node : TrieNode < Meta > = this . $root ;
584
589
585
590
const onToken = ( token : string ) => {
@@ -594,12 +599,12 @@ export class HostnameTrie<Meta = any> extends Triebase<Meta> {
594
599
return false ;
595
600
} ;
596
601
597
- if ( suffix [ 0 ] === '.' ) {
598
- suffix = suffix . slice ( 1 ) ;
602
+ if ( hostnameFromIndex === 0 && suffix [ 0 ] === '.' ) {
603
+ hostnameFromIndex = 1 ;
599
604
}
600
605
601
606
// When walkHostnameTokens returns true, we should skip the rest
602
- if ( walkHostnameTokens ( suffix , onToken ) ) {
607
+ if ( walkHostnameTokens ( suffix , onToken , hostnameFromIndex ) ) {
603
608
return ;
604
609
}
605
610
@@ -634,3 +639,10 @@ export type Trie = ReturnType<typeof createTrie>;
634
639
// }
635
640
// return true;
636
641
// };
642
+
643
+ function subStringEqual ( needle : string , haystack : string , needleIndex = 0 ) {
644
+ for ( let i = 0 , l = haystack . length ; i < l ; i ++ ) {
645
+ if ( needle [ i + needleIndex ] !== haystack [ i ] ) return false ;
646
+ }
647
+ return true ;
648
+ }
0 commit comments