diff --git a/Build/lib/stable-sort-domain.test.ts b/Build/lib/stable-sort-domain.test.ts deleted file mode 100644 index 08ee65d1..00000000 --- a/Build/lib/stable-sort-domain.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { describe, it } from 'mocha'; -import { expect } from 'expect'; -import { sortDomains } from './stable-sort-domain'; - -describe('sortDomains', () => { - it('basic', () => { - expect(sortDomains([ - '.s3-website.ap-northeast-3.amazonaws.com', - '.s3.dualstack.ap-south-1.amazonaws.com', - '.s3-website.af-south-1.amazonaws.com' - ])).toStrictEqual([ - '.s3-website.af-south-1.amazonaws.com', - '.s3.dualstack.ap-south-1.amazonaws.com', - '.s3-website.ap-northeast-3.amazonaws.com' - ]); - - expect(sortDomains([ - '.s3.dualstack.ap-south-1.amazonaws.com', - '.s3-website.ap-northeast-3.amazonaws.com', - '.s3-website.af-south-1.amazonaws.com' - ])).toStrictEqual([ - '.s3-website.af-south-1.amazonaws.com', - '.s3.dualstack.ap-south-1.amazonaws.com', - '.s3-website.ap-northeast-3.amazonaws.com' - ]); - - expect(sortDomains([ - '.s3-website-us-west-2.amazonaws.com', - '.s3-1.amazonaws.com' - ])).toStrictEqual([ - '.s3-1.amazonaws.com', - '.s3-website-us-west-2.amazonaws.com' - ]); - - expect(sortDomains([ - '.s3-1.amazonaws.com', - '.s3-website-us-west-2.amazonaws.com' - ])).toStrictEqual([ - '.s3-1.amazonaws.com', - '.s3-website-us-west-2.amazonaws.com' - ]); - - expect( - sortDomains([ - '.s3-deprecated.us-west-2.amazonaws.com', - '.s3-accesspoint.dualstack.us-west-2.amazonaws.com', - '.s3.dualstack.us-west-2.amazonaws.com' - ]) - ).toStrictEqual([ - '.s3.dualstack.us-west-2.amazonaws.com', - '.s3-deprecated.us-west-2.amazonaws.com', - '.s3-accesspoint.dualstack.us-west-2.amazonaws.com' - ]); - - expect( - sortDomains([ - '.s3-deprecated.us-west-2.amazonaws.com', - '.s3-accesspoint.dualstack.us-west-2.amazonaws.com', - '.s3.dualstack.us-west-2.amazonaws.com' - ]) - ).toStrictEqual([ - '.s3.dualstack.us-west-2.amazonaws.com', - '.s3-deprecated.us-west-2.amazonaws.com', - '.s3-accesspoint.dualstack.us-west-2.amazonaws.com' - ]); - - expect( - sortDomains([ - '.ec2-25-58-215-234.us-east-2.compute.amazonaws.com', - '.ec2-13-58-215-234.us-east-2.compute.amazonaws.com' - ]) - ).toStrictEqual([ - '.ec2-13-58-215-234.us-east-2.compute.amazonaws.com', - '.ec2-25-58-215-234.us-east-2.compute.amazonaws.com' - ]); - }); - - it('samsung test case', () => { - expect(sortDomains([ - '.notice.samsungcloudsolution.com', - 'samsungqbe.com', - 'samsungcloudsolution.com' - ])).toStrictEqual([ - 'samsungqbe.com', - 'samsungcloudsolution.com', - '.notice.samsungcloudsolution.com' - ]); - - expect( - sortDomains([ - '.notice.samsungcloudsolution.com', - '.vdterms.samsungcloudsolution.com', - '.gamespromotion.samsungcloudsolution.com', - '.samsunggiveaways.com', - '.gld.samsungosp.com', - 'samsungqbe.com', - 'samsungcloudsolution.com', - '.sas.samsungcloudsolution.com', - '.prov.samsungcloudsolution.com', - '.musicid.samsungcloudsolution.com', - '.amauthprd.samsungcloudsolution.com', - '.noticecdn.samsungcloudsolution.com', - '.abtauthprd.samsungcloudsolution.com', - '.noticefile.samsungcloudsolution.com', - '.prderrordumphsm.samsungcloudsolution.com', - 'samsungcloudsolution.net', - '.cdn.samsungcloudsolution.net', - '.lcprd1.samsungcloudsolution.net', - '.lcprd2.samsungcloudsolution.net', - '.samsungelectronics.com', - '.analytics-api.samsunghealthcn.com', - '.tracking.samsungknox.com', - '.analytics.samsungknox.com', - '.metrics.samsunglife.com', - '.smetrics.samsunglife.com', - '.nmetrics.samsungmobile.com', - '.rwww.samsungotn.net', - '.samsungpoland.com.pl' - ]) - ).toStrictEqual([ - '.gld.samsungosp.com', - '.rwww.samsungotn.net', - 'samsungqbe.com', - '.tracking.samsungknox.com', - '.analytics.samsungknox.com', - '.metrics.samsunglife.com', - '.smetrics.samsunglife.com', - '.nmetrics.samsungmobile.com', - '.analytics-api.samsunghealthcn.com', - '.samsunggiveaways.com', - '.samsungpoland.com.pl', - '.samsungelectronics.com', - 'samsungcloudsolution.com', - '.sas.samsungcloudsolution.com', - '.prov.samsungcloudsolution.com', - '.notice.samsungcloudsolution.com', - '.musicid.samsungcloudsolution.com', - '.vdterms.samsungcloudsolution.com', - '.amauthprd.samsungcloudsolution.com', - '.noticecdn.samsungcloudsolution.com', - '.abtauthprd.samsungcloudsolution.com', - '.noticefile.samsungcloudsolution.com', - '.gamespromotion.samsungcloudsolution.com', - '.prderrordumphsm.samsungcloudsolution.com', - 'samsungcloudsolution.net', - '.cdn.samsungcloudsolution.net', - '.lcprd1.samsungcloudsolution.net', - '.lcprd2.samsungcloudsolution.net' - ]); - }); -}); diff --git a/Build/lib/stable-sort-domain.ts b/Build/lib/stable-sort-domain.ts deleted file mode 100644 index 84777ff0..00000000 --- a/Build/lib/stable-sort-domain.ts +++ /dev/null @@ -1,62 +0,0 @@ -// tldts-experimental is way faster than tldts, but very little bit inaccurate -// (since it is hashes based). But the result is still deterministic, which is -// enough when sorting. -import * as tldts from 'tldts-experimental'; -import { looseTldtsOpt } from '../constants/loose-tldts-opt'; -import { fastStringCompare } from './misc'; - -export function compare(a: string, b: string) { - if (a === b) return 0; - return (a.length - b.length) || fastStringCompare(a, b); -} - -export function buildParseDomainMap(inputs: string[]) { - const domainMap = new Map(); - const subdomainMap = new Map(); - - for (let i = 0, len = inputs.length; i < len; i++) { - const cur = inputs[i]; - if (!domainMap.has(cur)) { - const parsed = tldts.parse(cur, looseTldtsOpt); - domainMap.set(cur, parsed.domain ?? cur); - // if (!subdomainMap.has(cur)) { - subdomainMap.set(cur, parsed.subdomain ?? cur); - } - } - - return { domainMap, subdomainMap }; -} - -export function sortDomains( - inputs: string[], - domainMap?: Map | null, - subdomainMap?: Map | null -) { - if (!domainMap || !subdomainMap) { - const { domainMap: dm, subdomainMap: sm } = buildParseDomainMap(inputs); - domainMap = dm; - subdomainMap = sm; - } - - const sorter = (a: string, b: string) => { - if (a === b) return 0; - - const main_domain_a = domainMap.get(a)!; - const main_domain_b = domainMap.get(b)!; - - let t = compare(main_domain_a, main_domain_b) - || compare( - /** subdomain_a */ subdomainMap.get(a)!, - /** subdomain_b */ subdomainMap.get(b)! - ); - if (t !== 0) return t; - - if (a !== main_domain_a || b !== main_domain_b) { - t = compare(a, b); - } - - return t; - }; - - return inputs.sort(sorter); -} diff --git a/Build/lib/trie.ts b/Build/lib/trie.ts index d512cac4..6abecd53 100644 --- a/Build/lib/trie.ts +++ b/Build/lib/trie.ts @@ -238,11 +238,11 @@ abstract class Triebase { private walk( onMatches: (suffix: string[], subdomain: boolean, meta: Meta) => void, + withSort = false, initialNode = this.$root, - initialSuffix: string[] = [], - withSort = false + initialSuffix: string[] = [] ) { - const bfsImpl = withSort ? Triebase.dfsWithSort : Triebase.dfs; + const dfsImpl = withSort ? Triebase.dfsWithSort : Triebase.dfs; const nodeStack: Array> = []; nodeStack.push(initialNode); @@ -255,7 +255,7 @@ abstract class Triebase { let r; do { - r = bfsImpl(nodeStack, suffixStack); + r = dfsImpl(nodeStack, suffixStack); node = r[0]!; const suffix = r[1]; @@ -271,45 +271,6 @@ abstract class Triebase { return (a.length - b.length) || fastStringCompare(a, b); } - private walkWithSort( - onMatches: (suffix: string[], subdomain: boolean, meta: Meta) => void, - initialNode = this.$root, - initialSuffix: string[] = [] - ) { - const nodeStack: Array> = []; - nodeStack.push(initialNode); - - // Resolving initial string (begin the start of the stack) - const suffixStack: string[][] = []; - suffixStack.push(initialSuffix); - - let node: TrieNode = initialNode; - let child: Map> = node[2]; - - do { - node = nodeStack.pop()!; - const suffix = suffixStack.pop()!; - child = node[2]; - if (child.size) { - const keys = Array.from(child.keys()).sort(Triebase.compare); - - for (let i = 0, l = keys.length; i < l; i++) { - const key = keys[i]; - const childNode = child.get(key)!; - - // Pushing the child node to the stack for next iteration of DFS - nodeStack.push(childNode); - suffixStack.push([key, ...suffix]); - } - } - - // If the node is a sentinel, we push the suffix to the results - if (getBit(node[0], START)) { - onMatches(suffix, getBit(node[0], INCLUDE_ALL_SUBDOMAIN), node[4]); - } - } while (nodeStack.length); - }; - protected getSingleChildLeaf(tokens: string[]): FindSingleChildLeafResult | null { let toPrune: TrieNode | null = null; let tokenToPrune: string | null = null; @@ -371,6 +332,7 @@ abstract class Triebase { this.walk( onMatches, + false, res.node, // Performing DFS from prefix inputTokens ); @@ -421,11 +383,7 @@ abstract class Triebase { onSuffix(toASCII(fastStringArrayJoin(suffix, '.')), subdomain); }; - if (withSort) { - this.walkWithSort(handleSuffix); - } else { - this.walk(handleSuffix); - } + this.walk(handleSuffix, withSort); } public dump(onSuffix: (suffix: string) => void, withSort?: boolean): void; @@ -443,11 +401,7 @@ abstract class Triebase { results.push(subdomain ? '.' + d : d); }; - if (withSort) { - this.walkWithSort(handleSuffix); - } else { - this.walk(handleSuffix); - } + this.walk(handleSuffix, withSort); return results; }; @@ -461,11 +415,7 @@ abstract class Triebase { ? (_suffix: string[], _subdomain: boolean, meta: Meta) => onMeta(meta) : (_suffix: string[], _subdomain: boolean, meta: Meta) => results.push(meta); - if (withSort) { - this.walkWithSort(handleMeta); - } else { - this.walk(handleMeta); - } + this.walk(handleMeta, withSort); return results; }; @@ -485,11 +435,7 @@ abstract class Triebase { results.push([subdomain ? '.' + d : d, meta]); }; - if (withSort) { - this.walkWithSort(handleSuffix); - } else { - this.walk(handleSuffix); - } + this.walk(handleSuffix, withSort); return results; };