hntrie 0.0.0 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tlds.d.mts +5 -0
- package/dist/_tlds.d.ts +5 -0
- package/dist/_tlds.js +1 -0
- package/dist/_tlds.mjs +1 -0
- package/dist/_utils.d.mts +38 -0
- package/dist/_utils.d.ts +38 -0
- package/dist/_utils.js +1 -0
- package/dist/_utils.mjs +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/smol.d.ts +44 -0
- package/dist/smol.js +1 -0
- package/dist/smol.mjs +1 -0
- package/package.json +60 -8
package/dist/_tlds.d.mts
ADDED
package/dist/_tlds.d.ts
ADDED
package/dist/_tlds.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});let e=["com","org","net","io","co","me","tv","ai","info","biz","xyz","app","dev","moe","shop","online","top","site","club","store","tech","blog","live","gov","uk","de","us","eu","ca","au","jp","cn","in","br","fr","ru"],o=new Map,t=new Map;for(let r=0,p=e.length;r<p;r++){let p=r.toString(36);o.set(e[r],p),t.set(p,e[r])}exports.ID_TO_TLD=t,exports.TLDS=e,exports.TLD_TO_ID=o;
|
package/dist/_tlds.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=["com","org","net","io","co","me","tv","ai","info","biz","xyz","app","dev","moe","shop","online","top","site","club","store","tech","blog","live","gov","uk","de","us","eu","ca","au","jp","cn","in","br","fr","ru"],t=new Map,o=new Map;for(let n=0,i=e.length;n<i;n++){let i=n.toString(36);t.set(e[n],i),o.set(i,e[n])}let n=t,i=o;export{i as ID_TO_TLD,e as TLDS,n as TLD_TO_ID};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
declare const RADIX_SEP = "|";
|
|
2
|
+
/** Minimal node shape shared by TrieNode<T> and SmolNode */
|
|
3
|
+
interface BaseNode {
|
|
4
|
+
/** key — the label (or radix-compressed labels joined by RADIX_SEP) */
|
|
5
|
+
k: string;
|
|
6
|
+
/** children map — label → child node, null when leaf */
|
|
7
|
+
c: Map<string, BaseNode> | null;
|
|
8
|
+
/** flags — bitmask of FLAG_EXACT / FLAG_SUBDOMAIN */
|
|
9
|
+
f: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Walk hostname labels right-to-left (TLD first), calling `onLabel` for each.
|
|
13
|
+
* The TLD label is compressed to a single-char numeric ID if it's a known TLD.
|
|
14
|
+
* Returns `false` if the callback signaled early exit, `true` if fully walked.
|
|
15
|
+
* Strips a single trailing dot if present.
|
|
16
|
+
*/
|
|
17
|
+
declare function walkHostname(hostname: string, onLabel: (label: string) => boolean | void): boolean;
|
|
18
|
+
declare function splitHostname(hostname: string): string[];
|
|
19
|
+
declare function labelsToHostname(labels: string[]): string;
|
|
20
|
+
/** Walk hostname string, returning the leaf node or null. */
|
|
21
|
+
declare function trieWalkFindH<N extends BaseNode>(root: N, hostname: string): N | null;
|
|
22
|
+
/** Walk labels array, returning the leaf node or null. */
|
|
23
|
+
declare function trieWalkFind<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
24
|
+
/** Walk labels in compacted (radix) mode, returning the leaf node or null. */
|
|
25
|
+
declare function trieWalkFindCompacted<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
26
|
+
/** Radix-compress single-child chains in place. */
|
|
27
|
+
declare function trieCompressNode<N extends BaseNode>(node: N): void;
|
|
28
|
+
/**
|
|
29
|
+
* Expand radix-compressed nodes back to one-label-per-node.
|
|
30
|
+
* `createEmpty` builds a bare node (no value fields).
|
|
31
|
+
* `copyTail` copies value/data fields from the original compressed node to the expanded tail.
|
|
32
|
+
*/
|
|
33
|
+
declare function trieExpandNode<N extends BaseNode>(node: N, createEmpty: (key: string) => N, copyTail: (tail: N, original: N) => void): void;
|
|
34
|
+
/** Remove empty leaf nodes bottom-up along the label path. */
|
|
35
|
+
declare function trieCleanup<N extends BaseNode>(root: N, labels: string[]): void;
|
|
36
|
+
|
|
37
|
+
export { RADIX_SEP, labelsToHostname, splitHostname, trieCleanup, trieCompressNode, trieExpandNode, trieWalkFind, trieWalkFindCompacted, trieWalkFindH, walkHostname };
|
|
38
|
+
export type { BaseNode };
|
package/dist/_utils.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
declare const RADIX_SEP = "|";
|
|
2
|
+
/** Minimal node shape shared by TrieNode<T> and SmolNode */
|
|
3
|
+
interface BaseNode {
|
|
4
|
+
/** key — the label (or radix-compressed labels joined by RADIX_SEP) */
|
|
5
|
+
k: string;
|
|
6
|
+
/** children map — label → child node, null when leaf */
|
|
7
|
+
c: Map<string, BaseNode> | null;
|
|
8
|
+
/** flags — bitmask of FLAG_EXACT / FLAG_SUBDOMAIN */
|
|
9
|
+
f: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Walk hostname labels right-to-left (TLD first), calling `onLabel` for each.
|
|
13
|
+
* The TLD label is compressed to a single-char numeric ID if it's a known TLD.
|
|
14
|
+
* Returns `false` if the callback signaled early exit, `true` if fully walked.
|
|
15
|
+
* Strips a single trailing dot if present.
|
|
16
|
+
*/
|
|
17
|
+
declare function walkHostname(hostname: string, onLabel: (label: string) => boolean | void): boolean;
|
|
18
|
+
declare function splitHostname(hostname: string): string[];
|
|
19
|
+
declare function labelsToHostname(labels: string[]): string;
|
|
20
|
+
/** Walk hostname string, returning the leaf node or null. */
|
|
21
|
+
declare function trieWalkFindH<N extends BaseNode>(root: N, hostname: string): N | null;
|
|
22
|
+
/** Walk labels array, returning the leaf node or null. */
|
|
23
|
+
declare function trieWalkFind<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
24
|
+
/** Walk labels in compacted (radix) mode, returning the leaf node or null. */
|
|
25
|
+
declare function trieWalkFindCompacted<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
26
|
+
/** Radix-compress single-child chains in place. */
|
|
27
|
+
declare function trieCompressNode<N extends BaseNode>(node: N): void;
|
|
28
|
+
/**
|
|
29
|
+
* Expand radix-compressed nodes back to one-label-per-node.
|
|
30
|
+
* `createEmpty` builds a bare node (no value fields).
|
|
31
|
+
* `copyTail` copies value/data fields from the original compressed node to the expanded tail.
|
|
32
|
+
*/
|
|
33
|
+
declare function trieExpandNode<N extends BaseNode>(node: N, createEmpty: (key: string) => N, copyTail: (tail: N, original: N) => void): void;
|
|
34
|
+
/** Remove empty leaf nodes bottom-up along the label path. */
|
|
35
|
+
declare function trieCleanup<N extends BaseNode>(root: N, labels: string[]): void;
|
|
36
|
+
|
|
37
|
+
export { RADIX_SEP, labelsToHostname, splitHostname, trieCleanup, trieCompressNode, trieExpandNode, trieWalkFind, trieWalkFindCompacted, trieWalkFindH, walkHostname };
|
|
38
|
+
export type { BaseNode };
|
package/dist/_utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./_tlds.js");function t(t,l){let r=t.length;if(0===r)return!1!==l("");46===t.codePointAt(r-1)&&r--;let n=t.lastIndexOf(".",r-1),o=t.slice(n+1,r);if(!1===l(e.TLD_TO_ID.get(o)??o))return!1;for(;n>=0;)if(r=n,n=t.lastIndexOf(".",r-1),!1===l(t.slice(n+1,r)))return!1;return!0}exports.RADIX_SEP="|",exports.labelsToHostname=function(t){let l=t.length,r=t[l-1];for(let e=l-2;e>0;e--)r+="."+t[e];if(l>1){let l=t[0];r+="."+(e.ID_TO_TLD.get(l)??l)}return r},exports.splitHostname=function(e){let l=[];return t(e,e=>{l.push(e)}),l},exports.trieCleanup=function(e,t){let l=[e],r=e;for(let e of t){let t=r.c?.get(e);if(!t)return;l.push(t),r=t}for(let e=l.length-1;e>0;e--){let t=l[e];if(0!==t.f||null!==t.c&&t.c.size>0)break;let r=l[e-1];r.c?.delete(t.k),r.c?.size===0&&(r.c=null)}},exports.trieCompressNode=function e(t){if(null!==t.c){for(let l of t.c.values())e(l);for(let[e,l]of t.c)if(null!==l.c&&1===l.c.size&&0===l.f){let r=l.c.values().next().value;r.k=l.k+"|"+r.k,t.c.set(e,r)}}},exports.trieExpandNode=function e(t,l,r){if(null!==t.c)for(let[n,o]of[...t.c]){let f=o.k.split("|"),i=f.length;if(i>1){let u=l(f[0]),s=u;for(let e=1;e<i;e++){let t=l(f[e]);e===i-1&&(t.c=o.c,t.f=o.f,r(t,o)),s.c=new Map,s.c.set(f[e],t),s=t}t.c.set(n,u),e(s,l,r)}else e(o,l,r)}},exports.trieWalkFind=function(e,t){let l=e,r=t.length;for(let e=0;e<r;e++){let r=l.c?.get(t[e]);if(!r)return null;l=r}return l},exports.trieWalkFindCompacted=function(e,t){let l=e,r=0,n=t.length;for(;r<n;){let e=l.c?.get(t[r]);if(!e)return null;let o=e.k.split("|"),f=o.length;for(let e=0;e<f;e++){if(r>=n||o[e]!==t[r])return null;r++}l=e}return l},exports.trieWalkFindH=function(e,l){let r=e;return t(l,e=>{let t=r.c?.get(e);if(!t)return!1;r=t})?r:null},exports.walkHostname=t;
|
package/dist/_utils.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{TLD_TO_ID as e,ID_TO_TLD as t}from"./_tlds.mjs";let l="|";function n(t,l){let n=t.length;if(0===n)return!1!==l("");46===t.codePointAt(n-1)&&n--;let r=t.lastIndexOf(".",n-1),f=t.slice(r+1,n);if(!1===l(e.get(f)??f))return!1;for(;r>=0;)if(n=r,r=t.lastIndexOf(".",n-1),!1===l(t.slice(r+1,n)))return!1;return!0}function r(e){let t=[];return n(e,e=>{t.push(e)}),t}function f(e){let l=e.length,n=e[l-1];for(let t=l-2;t>0;t--)n+="."+e[t];if(l>1){let l=e[0];n+="."+(t.get(l)??l)}return n}function i(e,t){let l=e;return n(t,e=>{let t=l.c?.get(e);if(!t)return!1;l=t})?l:null}function u(e,t){let l=e,n=t.length;for(let e=0;e<n;e++){let n=l.c?.get(t[e]);if(!n)return null;l=n}return l}function o(e,t){let n=e,r=0,f=t.length;for(;r<f;){let e=n.c?.get(t[r]);if(!e)return null;let i=e.k.split(l),u=i.length;for(let e=0;e<u;e++){if(r>=f||i[e]!==t[r])return null;r++}n=e}return n}function c(e){if(null!==e.c){for(let t of e.c.values())c(t);for(let[t,n]of e.c)if(null!==n.c&&1===n.c.size&&0===n.f){let r=n.c.values().next().value;r.k=n.k+l+r.k,e.c.set(t,r)}}}function s(e,t,n){if(null!==e.c)for(let[r,f]of[...e.c]){let i=f.k.split(l),u=i.length;if(u>1){let l=t(i[0]),o=l;for(let e=1;e<u;e++){let l=t(i[e]);e===u-1&&(l.c=f.c,l.f=f.f,n(l,f)),o.c=new Map,o.c.set(i[e],l),o=l}e.c.set(r,l),s(o,t,n)}else s(f,t,n)}}function a(e,t){let l=[e],n=e;for(let e of t){let t=n.c?.get(e);if(!t)return;l.push(t),n=t}for(let e=l.length-1;e>0;e--){let t=l[e];if(0!==t.f||null!==t.c&&t.c.size>0)break;let n=l[e-1];n.c?.delete(t.k),n.c?.size===0&&(n.c=null)}}export{l as RADIX_SEP,f as labelsToHostname,r as splitHostname,a as trieCleanup,c as trieCompressNode,s as trieExpandNode,u as trieWalkFind,o as trieWalkFindCompacted,i as trieWalkFindH,n as walkHostname};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
interface TrieNode<T> {
|
|
2
|
+
/** key — the label (or radix-compressed labels joined by RADIX_SEP) */
|
|
3
|
+
k: string;
|
|
4
|
+
/** children map — label → child node, null when leaf */
|
|
5
|
+
c: Map<string, TrieNode<T>> | null;
|
|
6
|
+
/** flags — bitmask of FLAG_EXACT / FLAG_SUBDOMAIN */
|
|
7
|
+
f: number;
|
|
8
|
+
/** exact-match value */
|
|
9
|
+
e: T | undefined;
|
|
10
|
+
/** subdomain-match value */
|
|
11
|
+
s: T | undefined;
|
|
12
|
+
}
|
|
13
|
+
declare class HostnameTrie<T = boolean> {
|
|
14
|
+
/** @internal */
|
|
15
|
+
_root: TrieNode<T>;
|
|
16
|
+
/** @internal */
|
|
17
|
+
_compacted: boolean;
|
|
18
|
+
/** @internal */
|
|
19
|
+
_size: number;
|
|
20
|
+
constructor(from?: Iterable<string> | null);
|
|
21
|
+
get size(): number;
|
|
22
|
+
get compacted(): boolean;
|
|
23
|
+
add(hostname: string, value?: T): this;
|
|
24
|
+
addSubdomain(hostname: string, value?: T): this;
|
|
25
|
+
remove(hostname: string): boolean;
|
|
26
|
+
removeSubdomain(hostname: string): boolean;
|
|
27
|
+
delete(hostname: string): boolean;
|
|
28
|
+
has(hostname: string): boolean;
|
|
29
|
+
hasSubdomain(hostname: string): boolean;
|
|
30
|
+
match(hostname: string): T | null;
|
|
31
|
+
find(prefix: string): string[];
|
|
32
|
+
dump(cb: (hostname: string, includeSubdomain: boolean, value: T) => void): void;
|
|
33
|
+
compact(): this;
|
|
34
|
+
serialize(valueToString?: (value: T) => string): string;
|
|
35
|
+
static deserialize<T = boolean>(this: void, data: string, valueFromString?: (s: string) => T): HostnameTrie<T>;
|
|
36
|
+
toJSON(): string;
|
|
37
|
+
static fromJSON<T = boolean>(this: void, data: string, valueFromString?: (s: string) => T): HostnameTrie<T>;
|
|
38
|
+
[Symbol.iterator](): Generator<[string, T, 'exact' | 'subdomain']>;
|
|
39
|
+
/** @internal */
|
|
40
|
+
private _expandIfCompacted;
|
|
41
|
+
/** @internal Walk hostname string, creating nodes as needed. */
|
|
42
|
+
private _walkCreateH;
|
|
43
|
+
/** @internal Match hostname string in unfrozen mode. */
|
|
44
|
+
private _matchUnfrozenH;
|
|
45
|
+
/** @internal Match in compacted (radix) mode with subdomain tracking. */
|
|
46
|
+
private _matchCompacted;
|
|
47
|
+
/** @internal */
|
|
48
|
+
private _serializeNode;
|
|
49
|
+
/** @internal */
|
|
50
|
+
private _iterateNode;
|
|
51
|
+
/** @internal */
|
|
52
|
+
private _collectEntries;
|
|
53
|
+
/** @internal */
|
|
54
|
+
private _walkDump;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { HostnameTrie };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});var t,e=require("./_utils.js"),i=require("foxts/bitwise"),s=require("foxts/fast-string-array-join");let r="hntrie:1";function o(t){return{k:t,c:null,f:0,e:void 0,s:void 0}}function l(t,e){t.e=e.e,t.s=e.s}t=Symbol.iterator;class n{constructor(t){if(this._root=o(""),this._compacted=!1,this._size=0,t)for(let e of t)46===e.codePointAt(0)?this.addSubdomain(e.slice(1)):this.add(e)}get size(){return this._size}get compacted(){return this._compacted}add(t,e=!0){if(46===t.codePointAt(0))return this.addSubdomain(t.slice(1),e);this._expandIfCompacted();let s=this._walkCreateH(t);return i.missingBit(s.f,1)&&this._size++,s.f=i.setBit(s.f,1),s.e=e,this}addSubdomain(t,e=!0){this._expandIfCompacted();let s=this._walkCreateH(t);return i.missingBit(s.f,2)&&this._size++,s.f=i.setBit(s.f,2),s.s=e,this}remove(t){this._expandIfCompacted();let s=e.splitHostname(t),r=e.trieWalkFind(this._root,s);return!(!r||i.missingBit(r.f,1))&&(r.f=i.deleteBit(r.f,1),r.e=void 0,this._size--,e.trieCleanup(this._root,s),!0)}removeSubdomain(t){this._expandIfCompacted();let s=e.splitHostname(t),r=e.trieWalkFind(this._root,s);return!(!r||i.missingBit(r.f,2))&&(r.f=i.deleteBit(r.f,2),r.s=void 0,this._size--,e.trieCleanup(this._root,s),!0)}delete(t){return 46===t.codePointAt(0)?this.removeSubdomain(t.slice(1)):this.remove(t)}has(t){if(this._compacted){let s=e.splitHostname(t);return i.getBit(e.trieWalkFindCompacted(this._root,s)?.f??0,1)}return i.getBit(e.trieWalkFindH(this._root,t)?.f??0,1)}hasSubdomain(t){if(this._compacted){let s=e.splitHostname(t);return i.getBit(e.trieWalkFindCompacted(this._root,s)?.f??0,2)}return i.getBit(e.trieWalkFindH(this._root,t)?.f??0,2)}match(t){if(this._compacted){let i=e.splitHostname(t);return this._matchCompacted(i)}return this._matchUnfrozenH(t)}find(t){let s=46===t.codePointAt(0),r=s?t.slice(1):t,o=e.splitHostname(r),l=e.trieWalkFind(this._root,o),n=[];if(!l)return n;if(s){if(i.getBit(l.f,2)&&n.push("."+r),null!==l.c)for(let t of l.c.values())this._collectEntries(t,o,n)}else this._collectEntries(l,o.slice(0,-1),n);return n}dump(t){this._walkDump(this._root,[],t)}compact(){return this._compacted||(e.trieCompressNode(this._root),this._compacted=!0),this}serialize(t){let e=[r];return this._serializeNode(this._root,e,t),s.fastStringArrayJoin(e,"\n")}static deserialize(t,s){let l=new n,a=t.split("\n");if(a[0]!==r)throw Error("Invalid hntrie serialization format");let f=0,c=[[l._root,-1]],h=a.length;for(let t=1;t<h;t++){let r=a[t];if(0===r.length)continue;let l=r.split(" "),n=Number.parseInt(l[0],36),h=l[1],u=Number.parseInt(l[2],36),d=l[3]||"",_=l[4]||"",p=o(h);for(p.f=u,i.getBit(u,1)&&(p.e=!d||(s?s(d):JSON.parse(d)),f++),i.getBit(u,2)&&(p.s=!_||(s?s(_):JSON.parse(_)),f++);c.length>1&&c[c.length-1][1]>=n;)c.pop();let m=c[c.length-1][0];null===m.c&&(m.c=new Map);let g=h.includes(e.RADIX_SEP)?h.slice(0,h.indexOf(e.RADIX_SEP)):h;m.c.set(g,p),c.push([p,n])}return l._size=f,l._compacted=function t(i){if(i.k.includes(e.RADIX_SEP))return!0;if(null!==i.c){for(let e of i.c.values())if(t(e))return!0}return!1}(l._root),l}toJSON(){return this.serialize()}static fromJSON(t,e){return n.deserialize(t,e)}*[t](){yield*this._iterateNode(this._root,[])}_expandIfCompacted(){this._compacted&&(e.trieExpandNode(this._root,o,l),this._compacted=!1)}_walkCreateH(t){let i=this._root;return e.walkHostname(t,t=>{null===i.c&&(i.c=new Map);let e=i.c.get(t);e||(e=o(t),i.c.set(t,e)),i=e}),i}_matchUnfrozenH(t){let s=this._root,r=null;return e.walkHostname(t,t=>{let e=s.c?.get(t);if(!e)return!1;s=e,i.getBit(s.f,2)&&(r=s.s)})&&i.getBit(s.f,1)?s.e:r}_matchCompacted(t){let s=this._root,r=null,o=0,l=t.length;for(;o<l;){let n=s.c?.get(t[o]);if(!n)return r;let a=n.k.split(e.RADIX_SEP),f=a.length;for(let e=0;e<f;e++){if(o>=l||a[e]!==t[o])return r;o++}s=n,i.getBit(s.f,2)&&(r=s.s)}return i.getBit(s.f,1)?s.e:r}_serializeNode(t,e,s,r=-1){if(r>=0){let o="",l="";i.getBit(t.f,1)&&!0!==t.e&&(o=s?s(t.e):JSON.stringify(t.e)),i.getBit(t.f,2)&&!0!==t.s&&(l=s?s(t.s):JSON.stringify(t.s));let n=r.toString(36)+" "+t.k+" "+t.f.toString(36);(o||l)&&(n+=" "+o,l&&(n+=" "+l)),e.push(n)}if(null!==t.c)for(let i of t.c.values())this._serializeNode(i,e,s,r+1)}*_iterateNode(t,s){let r=""===t.k?[]:t.k.split(e.RADIX_SEP),o=r.length;for(let t=0;t<o;t++)s.push(r[t]);if(i.getBit(t.f,1)&&(yield[e.labelsToHostname(s),t.e,"exact"]),i.getBit(t.f,2)&&(yield[e.labelsToHostname(s),t.s,"subdomain"]),null!==t.c)for(let e of t.c.values())yield*this._iterateNode(e,s);for(let t=0;t<o;t++)s.pop()}_collectEntries(t,s,r){let o=""===t.k?[]:t.k.split(e.RADIX_SEP),l=o.length;for(let t=0;t<l;t++)s.push(o[t]);if(i.getBit(t.f,2)&&r.push("."+e.labelsToHostname(s)),i.getBit(t.f,1)&&r.push(e.labelsToHostname(s)),null!==t.c)for(let e of t.c.values())this._collectEntries(e,s,r);for(let t=0;t<l;t++)s.pop()}_walkDump(t,s,r){let o=""===t.k?[]:t.k.split(e.RADIX_SEP),l=o.length;for(let t=0;t<l;t++)s.push(o[t]);if(i.getBit(t.f,2)&&r(e.labelsToHostname(s),!0,t.s),i.getBit(t.f,1)&&r(e.labelsToHostname(s),!1,t.e),null!==t.c)for(let e of t.c.values())this._walkDump(e,s,r);for(let t=0;t<l;t++)s.pop()}}exports.HostnameTrie=n;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t;import{splitHostname as e,trieWalkFind as i,trieCleanup as r,trieWalkFindCompacted as o,trieWalkFindH as s,trieCompressNode as l,RADIX_SEP as n,trieExpandNode as f,walkHostname as a,labelsToHostname as c}from"./_utils.mjs";import{missingBit as h,setBit as u,deleteBit as d,getBit as _}from"foxts/bitwise";import{fastStringArrayJoin as p}from"foxts/fast-string-array-join";let m="hntrie:1";function g(t){return{k:t,c:null,f:0,e:void 0,s:void 0}}function z(t,e){t.e=e.e,t.s=e.s}t=Symbol.iterator;class k{constructor(t){if(this._root=g(""),this._compacted=!1,this._size=0,t)for(let e of t)46===e.codePointAt(0)?this.addSubdomain(e.slice(1)):this.add(e)}get size(){return this._size}get compacted(){return this._compacted}add(t,e=!0){if(46===t.codePointAt(0))return this.addSubdomain(t.slice(1),e);this._expandIfCompacted();let i=this._walkCreateH(t);return h(i.f,1)&&this._size++,i.f=u(i.f,1),i.e=e,this}addSubdomain(t,e=!0){this._expandIfCompacted();let i=this._walkCreateH(t);return h(i.f,2)&&this._size++,i.f=u(i.f,2),i.s=e,this}remove(t){this._expandIfCompacted();let o=e(t),s=i(this._root,o);return!(!s||h(s.f,1))&&(s.f=d(s.f,1),s.e=void 0,this._size--,r(this._root,o),!0)}removeSubdomain(t){this._expandIfCompacted();let o=e(t),s=i(this._root,o);return!(!s||h(s.f,2))&&(s.f=d(s.f,2),s.s=void 0,this._size--,r(this._root,o),!0)}delete(t){return 46===t.codePointAt(0)?this.removeSubdomain(t.slice(1)):this.remove(t)}has(t){if(this._compacted){let i=e(t);return _(o(this._root,i)?.f??0,1)}return _(s(this._root,t)?.f??0,1)}hasSubdomain(t){if(this._compacted){let i=e(t);return _(o(this._root,i)?.f??0,2)}return _(s(this._root,t)?.f??0,2)}match(t){if(this._compacted){let i=e(t);return this._matchCompacted(i)}return this._matchUnfrozenH(t)}find(t){let r=46===t.codePointAt(0),o=r?t.slice(1):t,s=e(o),l=i(this._root,s),n=[];if(!l)return n;if(r){if(_(l.f,2)&&n.push("."+o),null!==l.c)for(let t of l.c.values())this._collectEntries(t,s,n)}else this._collectEntries(l,s.slice(0,-1),n);return n}dump(t){this._walkDump(this._root,[],t)}compact(){return this._compacted||(l(this._root),this._compacted=!0),this}serialize(t){let e=[m];return this._serializeNode(this._root,e,t),p(e,"\n")}static deserialize(t,e){let i=new k,r=t.split("\n");if(r[0]!==m)throw Error("Invalid hntrie serialization format");let o=0,s=[[i._root,-1]],l=r.length;for(let t=1;t<l;t++){let i=r[t];if(0===i.length)continue;let l=i.split(" "),f=Number.parseInt(l[0],36),a=l[1],c=Number.parseInt(l[2],36),h=l[3]||"",u=l[4]||"",d=g(a);for(d.f=c,_(c,1)&&(d.e=!h||(e?e(h):JSON.parse(h)),o++),_(c,2)&&(d.s=!u||(e?e(u):JSON.parse(u)),o++);s.length>1&&s[s.length-1][1]>=f;)s.pop();let p=s[s.length-1][0];null===p.c&&(p.c=new Map);let m=a.includes(n)?a.slice(0,a.indexOf(n)):a;p.c.set(m,d),s.push([d,f])}return i._size=o,i._compacted=function t(e){if(e.k.includes(n))return!0;if(null!==e.c){for(let i of e.c.values())if(t(i))return!0}return!1}(i._root),i}toJSON(){return this.serialize()}static fromJSON(t,e){return k.deserialize(t,e)}*[t](){yield*this._iterateNode(this._root,[])}_expandIfCompacted(){this._compacted&&(f(this._root,g,z),this._compacted=!1)}_walkCreateH(t){let e=this._root;return a(t,t=>{null===e.c&&(e.c=new Map);let i=e.c.get(t);i||(i=g(t),e.c.set(t,i)),e=i}),e}_matchUnfrozenH(t){let e=this._root,i=null;return a(t,t=>{let r=e.c?.get(t);if(!r)return!1;_((e=r).f,2)&&(i=e.s)})&&_(e.f,1)?e.e:i}_matchCompacted(t){let e=this._root,i=null,r=0,o=t.length;for(;r<o;){let s=e.c?.get(t[r]);if(!s)return i;let l=s.k.split(n),f=l.length;for(let e=0;e<f;e++){if(r>=o||l[e]!==t[r])return i;r++}_((e=s).f,2)&&(i=e.s)}return _(e.f,1)?e.e:i}_serializeNode(t,e,i,r=-1){if(r>=0){let o="",s="";_(t.f,1)&&!0!==t.e&&(o=i?i(t.e):JSON.stringify(t.e)),_(t.f,2)&&!0!==t.s&&(s=i?i(t.s):JSON.stringify(t.s));let l=r.toString(36)+" "+t.k+" "+t.f.toString(36);(o||s)&&(l+=" "+o,s&&(l+=" "+s)),e.push(l)}if(null!==t.c)for(let o of t.c.values())this._serializeNode(o,e,i,r+1)}*_iterateNode(t,e){let i=""===t.k?[]:t.k.split(n),r=i.length;for(let t=0;t<r;t++)e.push(i[t]);if(_(t.f,1)&&(yield[c(e),t.e,"exact"]),_(t.f,2)&&(yield[c(e),t.s,"subdomain"]),null!==t.c)for(let i of t.c.values())yield*this._iterateNode(i,e);for(let t=0;t<r;t++)e.pop()}_collectEntries(t,e,i){let r=""===t.k?[]:t.k.split(n),o=r.length;for(let t=0;t<o;t++)e.push(r[t]);if(_(t.f,2)&&i.push("."+c(e)),_(t.f,1)&&i.push(c(e)),null!==t.c)for(let r of t.c.values())this._collectEntries(r,e,i);for(let t=0;t<o;t++)e.pop()}_walkDump(t,e,i){let r=""===t.k?[]:t.k.split(n),o=r.length;for(let t=0;t<o;t++)e.push(r[t]);if(_(t.f,2)&&i(c(e),!0,t.s),_(t.f,1)&&i(c(e),!1,t.e),null!==t.c)for(let r of t.c.values())this._walkDump(r,e,i);for(let t=0;t<o;t++)e.pop()}}export{k as HostnameTrie};
|
package/dist/smol.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
interface SmolNode {
|
|
2
|
+
/** key — the label (or radix-compressed labels joined by RADIX_SEP) */
|
|
3
|
+
k: string;
|
|
4
|
+
/** children map — label → child node, null when leaf */
|
|
5
|
+
c: Map<string, SmolNode> | null;
|
|
6
|
+
/** flags — bitmask of FLAG_EXACT / FLAG_SUBDOMAIN */
|
|
7
|
+
f: number;
|
|
8
|
+
}
|
|
9
|
+
declare class HostnameSmolTrie {
|
|
10
|
+
/** @internal */
|
|
11
|
+
_root: SmolNode;
|
|
12
|
+
/** @internal */
|
|
13
|
+
_compacted: boolean;
|
|
14
|
+
constructor(from?: Iterable<string> | null);
|
|
15
|
+
get compacted(): boolean;
|
|
16
|
+
add(hostname: string): this;
|
|
17
|
+
addSubdomain(hostname: string): this;
|
|
18
|
+
remove(hostname: string): boolean;
|
|
19
|
+
removeSubdomain(hostname: string): boolean;
|
|
20
|
+
delete(hostname: string): boolean;
|
|
21
|
+
whitelist(hostname: string): void;
|
|
22
|
+
has(hostname: string): boolean;
|
|
23
|
+
hasSubdomain(hostname: string): boolean;
|
|
24
|
+
match(hostname: string): boolean;
|
|
25
|
+
contains(hostname: string): boolean;
|
|
26
|
+
find(prefix: string): string[];
|
|
27
|
+
compact(): this;
|
|
28
|
+
dump(cb: (hostname: string, includeSubdomain: boolean) => void): void;
|
|
29
|
+
static load(this: void, entries: string[]): HostnameSmolTrie;
|
|
30
|
+
/** @internal */
|
|
31
|
+
private _expandIfCompacted;
|
|
32
|
+
/** @internal Walk hostname, creating nodes. Returns null if covered by ancestor subdomain. */
|
|
33
|
+
private _walkCreateOrCovered;
|
|
34
|
+
/** @internal Match hostname string in unfrozen mode. */
|
|
35
|
+
private _matchUnfrozenH;
|
|
36
|
+
/** @internal */
|
|
37
|
+
private _matchCompacted;
|
|
38
|
+
/** @internal */
|
|
39
|
+
private _collectEntries;
|
|
40
|
+
/** @internal */
|
|
41
|
+
private _walkDump;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { HostnameSmolTrie };
|
package/dist/smol.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});var t=require("./_utils.js"),e=require("foxts/bitwise");function i(t){return{k:t,c:null,f:0}}let o=require("foxts/noop").noop;exports.HostnameSmolTrie=class r{constructor(t){if(this._root=i(""),this._compacted=!1,t)for(let e of t)46===e.codePointAt(0)?this.addSubdomain(e.slice(1)):this.add(e)}get compacted(){return this._compacted}add(t){if(46===t.codePointAt(0))return this.addSubdomain(t.slice(1));this._expandIfCompacted();let i=this._walkCreateOrCovered(t);return null===i||(i.f=e.setBit(i.f,1)),this}addSubdomain(t){this._expandIfCompacted();let i=this._walkCreateOrCovered(t);return null===i||e.missingBit(i.f,2)&&(i.c=null,i.f=e.setBit(i.f,2),i.f=e.deleteBit(i.f,1)),this}remove(i){this._expandIfCompacted();let o=t.splitHostname(i),r=t.trieWalkFind(this._root,o);return!(!r||e.missingBit(r.f,1))&&(r.f=e.deleteBit(r.f,1),t.trieCleanup(this._root,o),!0)}removeSubdomain(i){this._expandIfCompacted();let o=t.splitHostname(i),r=t.trieWalkFind(this._root,o);return!(!r||e.missingBit(r.f,2))&&(r.f=e.deleteBit(r.f,2),t.trieCleanup(this._root,o),!0)}delete(t){return 46===t.codePointAt(0)?this.removeSubdomain(t.slice(1)):this.remove(t)}whitelist(i){this._expandIfCompacted();let o=46===i.codePointAt(0),r=o?i.slice(1):i,s=t.splitHostname(r),l=t.trieWalkFind(this._root,s);l&&(o?(l.f=0,l.c=null):(l.f=e.deleteBit(l.f,1),l.f=e.deleteBit(l.f,2)),t.trieCleanup(this._root,s))}has(i){if(this._compacted){let o=t.splitHostname(i);return e.getBit(t.trieWalkFindCompacted(this._root,o)?.f??0,1)}return e.getBit(t.trieWalkFindH(this._root,i)?.f??0,1)}hasSubdomain(i){if(this._compacted){let o=t.splitHostname(i);return e.getBit(t.trieWalkFindCompacted(this._root,o)?.f??0,2)}return e.getBit(t.trieWalkFindH(this._root,i)?.f??0,2)}match(e){if(this._compacted){let i=t.splitHostname(e);return this._matchCompacted(i)}return this._matchUnfrozenH(e)}contains(t){return this.match(t)}find(i){let o=46===i.codePointAt(0),r=o?i.slice(1):i,s=t.splitHostname(r),l=t.trieWalkFind(this._root,s),n=[];if(!l)return n;if(o){if(e.getBit(l.f,2)&&n.push("."+r),null!==l.c)for(let t of l.c.values())this._collectEntries(t,s,n)}else this._collectEntries(l,s.slice(0,-1),n);return n}compact(){return this._compacted||(t.trieCompressNode(this._root),this._compacted=!0),this}dump(t){this._walkDump(this._root,[],t)}static load(t){let e=new r,i=t.length;for(let o=0;o<i;o++){let i=t[o];46===i.codePointAt(0)?e.addSubdomain(i.slice(1)):e.add(i)}return e}_expandIfCompacted(){this._compacted&&(t.trieExpandNode(this._root,i,o),this._compacted=!1)}_walkCreateOrCovered(o){let r=this._root;return t.walkHostname(o,t=>{null===r.c&&(r.c=new Map);let o=r.c.get(t);if(o||(o=i(t),r.c.set(t,o)),r=o,e.getBit(r.f,2))return!1})?r:null}_matchUnfrozenH(i){let o=this._root;return t.walkHostname(i,t=>{let i=o.c?.get(t);return!!i&&(o=i,!e.getBit(o.f,2)&&void 0)})?0!==o.f:e.getBit(o.f,2)}_matchCompacted(i){let o=this._root,r=0,s=i.length;for(;r<s;){let l=o.c?.get(i[r]);if(!l)return!1;let n=l.k.split(t.RADIX_SEP),a=n.length;for(let t=0;t<a;t++){if(r>=s||n[t]!==i[r])return!1;r++}if(o=l,e.getBit(o.f,2))return!0}return 0!==o.f}_collectEntries(i,o,r){let s=""===i.k?[]:i.k.split(t.RADIX_SEP),l=s.length;for(let t=0;t<l;t++)o.push(s[t]);if(e.getBit(i.f,2)?r.push("."+t.labelsToHostname(o)):e.getBit(i.f,1)&&r.push(t.labelsToHostname(o)),null!==i.c&&e.missingBit(i.f,2))for(let t of i.c.values())this._collectEntries(t,o,r);for(let t=0;t<l;t++)o.pop()}_walkDump(i,o,r){let s=""===i.k?[]:i.k.split(t.RADIX_SEP),l=s.length;for(let t=0;t<l;t++)o.push(s[t]);if(e.getBit(i.f,2)?r(t.labelsToHostname(o),!0):e.getBit(i.f,1)&&r(t.labelsToHostname(o),!1),null!==i.c&&e.missingBit(i.f,2))for(let t of i.c.values())this._walkDump(t,o,r);for(let t=0;t<l;t++)o.pop()}};
|
package/dist/smol.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{splitHostname as t,trieWalkFind as e,trieCleanup as o,trieWalkFindCompacted as r,trieWalkFindH as i,trieCompressNode as l,trieExpandNode as s,walkHostname as f,RADIX_SEP as n,labelsToHostname as c}from"./_utils.mjs";import{setBit as h,missingBit as a,deleteBit as u,getBit as d}from"foxts/bitwise";import{noop as m}from"foxts/noop";function _(t){return{k:t,c:null,f:0}}class p{constructor(t){if(this._root=_(""),this._compacted=!1,t)for(let e of t)46===e.codePointAt(0)?this.addSubdomain(e.slice(1)):this.add(e)}get compacted(){return this._compacted}add(t){if(46===t.codePointAt(0))return this.addSubdomain(t.slice(1));this._expandIfCompacted();let e=this._walkCreateOrCovered(t);return null===e||(e.f=h(e.f,1)),this}addSubdomain(t){this._expandIfCompacted();let e=this._walkCreateOrCovered(t);return null===e||a(e.f,2)&&(e.c=null,e.f=h(e.f,2),e.f=u(e.f,1)),this}remove(r){this._expandIfCompacted();let i=t(r),l=e(this._root,i);return!(!l||a(l.f,1))&&(l.f=u(l.f,1),o(this._root,i),!0)}removeSubdomain(r){this._expandIfCompacted();let i=t(r),l=e(this._root,i);return!(!l||a(l.f,2))&&(l.f=u(l.f,2),o(this._root,i),!0)}delete(t){return 46===t.codePointAt(0)?this.removeSubdomain(t.slice(1)):this.remove(t)}whitelist(r){this._expandIfCompacted();let i=46===r.codePointAt(0),l=t(i?r.slice(1):r),s=e(this._root,l);s&&(i?(s.f=0,s.c=null):(s.f=u(s.f,1),s.f=u(s.f,2)),o(this._root,l))}has(e){if(this._compacted){let o=t(e);return d(r(this._root,o)?.f??0,1)}return d(i(this._root,e)?.f??0,1)}hasSubdomain(e){if(this._compacted){let o=t(e);return d(r(this._root,o)?.f??0,2)}return d(i(this._root,e)?.f??0,2)}match(e){if(this._compacted){let o=t(e);return this._matchCompacted(o)}return this._matchUnfrozenH(e)}contains(t){return this.match(t)}find(o){let r=46===o.codePointAt(0),i=r?o.slice(1):o,l=t(i),s=e(this._root,l),f=[];if(!s)return f;if(r){if(d(s.f,2)&&f.push("."+i),null!==s.c)for(let t of s.c.values())this._collectEntries(t,l,f)}else this._collectEntries(s,l.slice(0,-1),f);return f}compact(){return this._compacted||(l(this._root),this._compacted=!0),this}dump(t){this._walkDump(this._root,[],t)}static load(t){let e=new p,o=t.length;for(let r=0;r<o;r++){let o=t[r];46===o.codePointAt(0)?e.addSubdomain(o.slice(1)):e.add(o)}return e}_expandIfCompacted(){this._compacted&&(s(this._root,_,m),this._compacted=!1)}_walkCreateOrCovered(t){let e=this._root;return f(t,t=>{null===e.c&&(e.c=new Map);let o=e.c.get(t);if(o||(o=_(t),e.c.set(t,o)),d((e=o).f,2))return!1})?e:null}_matchUnfrozenH(t){let e=this._root;return f(t,t=>{let o=e.c?.get(t);if(!o||d((e=o).f,2))return!1})?0!==e.f:d(e.f,2)}_matchCompacted(t){let e=this._root,o=0,r=t.length;for(;o<r;){let i=e.c?.get(t[o]);if(!i)return!1;let l=i.k.split(n),s=l.length;for(let e=0;e<s;e++){if(o>=r||l[e]!==t[o])return!1;o++}if(d((e=i).f,2))return!0}return 0!==e.f}_collectEntries(t,e,o){let r=""===t.k?[]:t.k.split(n),i=r.length;for(let t=0;t<i;t++)e.push(r[t]);if(d(t.f,2)?o.push("."+c(e)):d(t.f,1)&&o.push(c(e)),null!==t.c&&a(t.f,2))for(let r of t.c.values())this._collectEntries(r,e,o);for(let t=0;t<i;t++)e.pop()}_walkDump(t,e,o){let r=""===t.k?[]:t.k.split(n),i=r.length;for(let t=0;t<i;t++)e.push(r[t]);if(d(t.f,2)?o(c(e),!0):d(t.f,1)&&o(c(e),!1),null!==t.c&&a(t.f,2))for(let r of t.c.values())this._walkDump(r,e,o);for(let t=0;t<i;t++)e.pop()}}export{p as HostnameSmolTrie};
|
package/package.json
CHANGED
|
@@ -1,11 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hntrie",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "The extremely fast Trie implementation optimized for Hostname.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/SukkaW/hntrie.git"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.mjs",
|
|
19
|
+
"require": "./dist/index.js",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./smol": {
|
|
23
|
+
"types": "./dist/smol.d.ts",
|
|
24
|
+
"import": "./dist/smol.mjs",
|
|
25
|
+
"require": "./dist/smol.js",
|
|
26
|
+
"default": "./dist/smol.js"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"Trie",
|
|
32
|
+
"Hostname",
|
|
33
|
+
"Radix Trie"
|
|
34
|
+
],
|
|
35
|
+
"author": "SukkaW <https://skk.moe>",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"foxts": "^5.5.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
42
|
+
"@swc-node/register": "^1.11.1",
|
|
43
|
+
"@swc/core": "^1.15.43",
|
|
44
|
+
"@types/mocha": "^10.0.10",
|
|
45
|
+
"bumpp": "^10.4.1",
|
|
46
|
+
"bunchee": "^6.11.0",
|
|
47
|
+
"earl": "^2.0.0",
|
|
48
|
+
"eslint": "^10.6.0",
|
|
49
|
+
"eslint-config-sukka": "^8.13.2",
|
|
50
|
+
"eslint-formatter-sukka": "^8.13.2",
|
|
51
|
+
"mocha": "^11.7.6",
|
|
52
|
+
"nyc": "^18.0.0",
|
|
53
|
+
"typescript": "^6.0.3"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"lint": "eslint --format=sukka .",
|
|
57
|
+
"build": "bunchee --minify --no-sourcemap",
|
|
58
|
+
"bench": "SWC_NODE_IGNORE_DYNAMIC=1 node src/index.bench.ts",
|
|
59
|
+
"test": "SWC_NODE_IGNORE_DYNAMIC=1 SWC_NODE_INLINE_SOURCE_MAP=1 nyc mocha --require @swc-node/register --full-trace 'src/**/*.test.ts'",
|
|
60
|
+
"prerelease": "pnpm run lint && pnpm run test && pnpm run build",
|
|
61
|
+
"release": "bumpp --install -r --all --commit \"release: %s\" --tag \"%s\""
|
|
62
|
+
}
|
|
11
63
|
}
|