hntrie 1.0.0 → 1.1.0
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/README.md +14 -1
- package/dist/_utils.d.mts +58 -1
- package/dist/_utils.d.ts +58 -1
- package/dist/_utils.js +1 -1
- package/dist/_utils.mjs +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/smol.d.ts +9 -0
- package/dist/smol.js +1 -1
- package/dist/smol.mjs +1 -1
- package/package.json +11 -8
package/README.md
CHANGED
|
@@ -64,6 +64,19 @@ const serialized = trie.serialize();
|
|
|
64
64
|
const restored = HostnameTrie.deserialize<string>(serialized);
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
`serializeTransferable`/`deserializeTransferable` do the same round-trip but through a packed binary `ArrayBuffer` instead of a string — pass it to `postMessage(buffer, [buffer])` and ownership transfers to the worker with zero copy, instead of paying for a full structured-clone of the trie:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// main thread
|
|
71
|
+
const buffer = trie.serializeTransferable();
|
|
72
|
+
worker.postMessage(buffer, [buffer]);
|
|
73
|
+
|
|
74
|
+
// inside the worker
|
|
75
|
+
self.onmessage = (event) => {
|
|
76
|
+
const trie = HostnameTrie.deserializeTransferable<string>(event.data);
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
67
80
|
Iterate entries directly, or stream them through a callback with `dump` (no intermediate array allocation, so entries can be pushed straight into whatever container is already on hand):
|
|
68
81
|
|
|
69
82
|
```ts
|
|
@@ -124,7 +137,7 @@ blocklist.match('bar.com');
|
|
|
124
137
|
|
|
125
138
|
Whitelisting only removes an entry that exists as its own node — if `foo.example.com` is already covered by a broader `.example.com` subdomain entry, whitelist that broader entry instead.
|
|
126
139
|
|
|
127
|
-
`HostnameSmolTrie` also supports `.compact()`, `.find(prefix)`,
|
|
140
|
+
`HostnameSmolTrie` also supports `.compact()`, `.find(prefix)`, `.dump()`/`HostnameSmolTrie.load()`, and `.serializeTransferable()`/`HostnameSmolTrie.deserializeTransferable()` for round-tripping, with the same semantics as `HostnameTrie` minus the stored values.
|
|
128
141
|
|
|
129
142
|
## License
|
|
130
143
|
|
package/dist/_utils.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ declare function trieWalkFindH<N extends BaseNode>(root: N, hostname: string): N
|
|
|
23
23
|
declare function trieWalkFind<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
24
24
|
/** Walk labels in compacted (radix) mode, returning the leaf node or null. */
|
|
25
25
|
declare function trieWalkFindCompacted<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
26
|
+
/** Whether any node in the tree has a radix-compressed (RADIX_SEP-joined) key. */
|
|
27
|
+
declare function trieHasCompressedKeys<N extends BaseNode>(node: N): boolean;
|
|
26
28
|
/** Radix-compress single-child chains in place. */
|
|
27
29
|
declare function trieCompressNode<N extends BaseNode>(node: N): void;
|
|
28
30
|
/**
|
|
@@ -33,6 +35,61 @@ declare function trieCompressNode<N extends BaseNode>(node: N): void;
|
|
|
33
35
|
declare function trieExpandNode<N extends BaseNode>(node: N, createEmpty: (key: string) => N, copyTail: (tail: N, original: N) => void): void;
|
|
34
36
|
/** Remove empty leaf nodes bottom-up along the label path. */
|
|
35
37
|
declare function trieCleanup<N extends BaseNode>(root: N, labels: string[]): void;
|
|
38
|
+
declare const BINARY_KIND_TRIE = 1;
|
|
39
|
+
declare const BINARY_KIND_SMOL = 2;
|
|
40
|
+
interface NodeBufferLike {
|
|
41
|
+
toString: (encoding: string, start: number, end: number) => string;
|
|
42
|
+
}
|
|
43
|
+
interface NodeBufferConstructorLike {
|
|
44
|
+
from: (buffer: ArrayBuffer) => NodeBufferLike;
|
|
45
|
+
}
|
|
46
|
+
declare global {
|
|
47
|
+
var Buffer: NodeBufferConstructorLike | undefined;
|
|
48
|
+
var window: unknown;
|
|
49
|
+
}
|
|
50
|
+
/** Minimal growable byte buffer — doubles capacity on overflow, like a Vec. */
|
|
51
|
+
declare class ByteWriter {
|
|
52
|
+
private _buf;
|
|
53
|
+
private _view;
|
|
54
|
+
private _len;
|
|
55
|
+
constructor(initialCapacity?: number);
|
|
56
|
+
private _ensure;
|
|
57
|
+
writeU8(value: number): void;
|
|
58
|
+
/** LEB128 unsigned varint — 1 byte for values < 128, growing as needed. */
|
|
59
|
+
writeVarint(value: number): void;
|
|
60
|
+
private _writeBytes;
|
|
61
|
+
/**
|
|
62
|
+
* Writes a varint byte-length prefix followed by the UTF-8 encoded string.
|
|
63
|
+
*
|
|
64
|
+
* Hostname labels are overwhelmingly ASCII, where one UTF-16 unit is one byte:
|
|
65
|
+
* the scan that proves it also yields the byte length, so the bytes go straight
|
|
66
|
+
* into the output with no TextEncoder call and no scratch round-trip. Anything
|
|
67
|
+
* non-ASCII falls back to encodeInto + copy.
|
|
68
|
+
*/
|
|
69
|
+
private _writeString;
|
|
70
|
+
/** Writes a varint byte-length prefix followed by the UTF-8 encoded string. */
|
|
71
|
+
writeKeyString(value: string): void;
|
|
72
|
+
/** Writes a value string, using 0 for the boolean `true` sentinel. */
|
|
73
|
+
writeValueString(value: string | null): void;
|
|
74
|
+
toArrayBuffer(): ArrayBuffer;
|
|
75
|
+
}
|
|
76
|
+
/** Reads back a buffer produced by `ByteWriter`. */
|
|
77
|
+
declare class ByteReader {
|
|
78
|
+
private readonly _view;
|
|
79
|
+
private readonly _bytes;
|
|
80
|
+
/** Node-only: wraps the same memory once, so decoding never allocates a view per string. */
|
|
81
|
+
private readonly _nodeBuffer;
|
|
82
|
+
private _pos;
|
|
83
|
+
constructor(buffer: ArrayBuffer);
|
|
84
|
+
get done(): boolean;
|
|
85
|
+
readU8(): number;
|
|
86
|
+
readVarint(): number;
|
|
87
|
+
private _readString;
|
|
88
|
+
readKeyString(): string;
|
|
89
|
+
readValueString(): string | null;
|
|
90
|
+
}
|
|
91
|
+
declare function writeBinaryHeader(writer: ByteWriter, kind: number): void;
|
|
92
|
+
declare function readBinaryHeader(reader: ByteReader, expectedKind: number): void;
|
|
36
93
|
|
|
37
|
-
export { RADIX_SEP, labelsToHostname, splitHostname, trieCleanup, trieCompressNode, trieExpandNode, trieWalkFind, trieWalkFindCompacted, trieWalkFindH, walkHostname };
|
|
94
|
+
export { BINARY_KIND_SMOL, BINARY_KIND_TRIE, ByteReader, ByteWriter, RADIX_SEP, labelsToHostname, readBinaryHeader, splitHostname, trieCleanup, trieCompressNode, trieExpandNode, trieHasCompressedKeys, trieWalkFind, trieWalkFindCompacted, trieWalkFindH, walkHostname, writeBinaryHeader };
|
|
38
95
|
export type { BaseNode };
|
package/dist/_utils.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ declare function trieWalkFindH<N extends BaseNode>(root: N, hostname: string): N
|
|
|
23
23
|
declare function trieWalkFind<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
24
24
|
/** Walk labels in compacted (radix) mode, returning the leaf node or null. */
|
|
25
25
|
declare function trieWalkFindCompacted<N extends BaseNode>(root: N, labels: string[]): N | null;
|
|
26
|
+
/** Whether any node in the tree has a radix-compressed (RADIX_SEP-joined) key. */
|
|
27
|
+
declare function trieHasCompressedKeys<N extends BaseNode>(node: N): boolean;
|
|
26
28
|
/** Radix-compress single-child chains in place. */
|
|
27
29
|
declare function trieCompressNode<N extends BaseNode>(node: N): void;
|
|
28
30
|
/**
|
|
@@ -33,6 +35,61 @@ declare function trieCompressNode<N extends BaseNode>(node: N): void;
|
|
|
33
35
|
declare function trieExpandNode<N extends BaseNode>(node: N, createEmpty: (key: string) => N, copyTail: (tail: N, original: N) => void): void;
|
|
34
36
|
/** Remove empty leaf nodes bottom-up along the label path. */
|
|
35
37
|
declare function trieCleanup<N extends BaseNode>(root: N, labels: string[]): void;
|
|
38
|
+
declare const BINARY_KIND_TRIE = 1;
|
|
39
|
+
declare const BINARY_KIND_SMOL = 2;
|
|
40
|
+
interface NodeBufferLike {
|
|
41
|
+
toString: (encoding: string, start: number, end: number) => string;
|
|
42
|
+
}
|
|
43
|
+
interface NodeBufferConstructorLike {
|
|
44
|
+
from: (buffer: ArrayBuffer) => NodeBufferLike;
|
|
45
|
+
}
|
|
46
|
+
declare global {
|
|
47
|
+
var Buffer: NodeBufferConstructorLike | undefined;
|
|
48
|
+
var window: unknown;
|
|
49
|
+
}
|
|
50
|
+
/** Minimal growable byte buffer — doubles capacity on overflow, like a Vec. */
|
|
51
|
+
declare class ByteWriter {
|
|
52
|
+
private _buf;
|
|
53
|
+
private _view;
|
|
54
|
+
private _len;
|
|
55
|
+
constructor(initialCapacity?: number);
|
|
56
|
+
private _ensure;
|
|
57
|
+
writeU8(value: number): void;
|
|
58
|
+
/** LEB128 unsigned varint — 1 byte for values < 128, growing as needed. */
|
|
59
|
+
writeVarint(value: number): void;
|
|
60
|
+
private _writeBytes;
|
|
61
|
+
/**
|
|
62
|
+
* Writes a varint byte-length prefix followed by the UTF-8 encoded string.
|
|
63
|
+
*
|
|
64
|
+
* Hostname labels are overwhelmingly ASCII, where one UTF-16 unit is one byte:
|
|
65
|
+
* the scan that proves it also yields the byte length, so the bytes go straight
|
|
66
|
+
* into the output with no TextEncoder call and no scratch round-trip. Anything
|
|
67
|
+
* non-ASCII falls back to encodeInto + copy.
|
|
68
|
+
*/
|
|
69
|
+
private _writeString;
|
|
70
|
+
/** Writes a varint byte-length prefix followed by the UTF-8 encoded string. */
|
|
71
|
+
writeKeyString(value: string): void;
|
|
72
|
+
/** Writes a value string, using 0 for the boolean `true` sentinel. */
|
|
73
|
+
writeValueString(value: string | null): void;
|
|
74
|
+
toArrayBuffer(): ArrayBuffer;
|
|
75
|
+
}
|
|
76
|
+
/** Reads back a buffer produced by `ByteWriter`. */
|
|
77
|
+
declare class ByteReader {
|
|
78
|
+
private readonly _view;
|
|
79
|
+
private readonly _bytes;
|
|
80
|
+
/** Node-only: wraps the same memory once, so decoding never allocates a view per string. */
|
|
81
|
+
private readonly _nodeBuffer;
|
|
82
|
+
private _pos;
|
|
83
|
+
constructor(buffer: ArrayBuffer);
|
|
84
|
+
get done(): boolean;
|
|
85
|
+
readU8(): number;
|
|
86
|
+
readVarint(): number;
|
|
87
|
+
private _readString;
|
|
88
|
+
readKeyString(): string;
|
|
89
|
+
readValueString(): string | null;
|
|
90
|
+
}
|
|
91
|
+
declare function writeBinaryHeader(writer: ByteWriter, kind: number): void;
|
|
92
|
+
declare function readBinaryHeader(reader: ByteReader, expectedKind: number): void;
|
|
36
93
|
|
|
37
|
-
export { RADIX_SEP, labelsToHostname, splitHostname, trieCleanup, trieCompressNode, trieExpandNode, trieWalkFind, trieWalkFindCompacted, trieWalkFindH, walkHostname };
|
|
94
|
+
export { BINARY_KIND_SMOL, BINARY_KIND_TRIE, ByteReader, ByteWriter, RADIX_SEP, labelsToHostname, readBinaryHeader, splitHostname, trieCleanup, trieCompressNode, trieExpandNode, trieHasCompressedKeys, trieWalkFind, trieWalkFindCompacted, trieWalkFindH, walkHostname, writeBinaryHeader };
|
|
38
95
|
export type { BaseNode };
|
package/dist/_utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./_tlds.js");function t(t,
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./_tlds.js");function t(t,r){let i=t.length;if(0===i)return!1!==r("");46===t.codePointAt(i-1)&&i--;let n=t.lastIndexOf(".",i-1),s=t.slice(n+1,i);if(!1===r(e.TLD_TO_ID.get(s)??s))return!1;for(;n>=0;)if(i=n,n=t.lastIndexOf(".",i-1),!1===r(t.slice(n+1,i)))return!1;return!0}let r=new TextEncoder,i=new TextDecoder(void 0,{fatal:!0}),n=new Uint8Array(765),s=String.fromCodePoint(66,117,102,102,101,114),l="u"<typeof window?globalThis[s]:void 0,o="function"==typeof l?.from?l.from.bind(l):null;exports.BINARY_KIND_SMOL=2,exports.BINARY_KIND_TRIE=1,exports.ByteReader=class{constructor(e){this._pos=0,this._view=new DataView(e),this._bytes=new Uint8Array(e),this._nodeBuffer=null===o?null:o(e)}get done(){return this._pos>=this._view.byteLength}readU8(){let e=this._view.getUint8(this._pos);return this._pos+=1,e}readVarint(){let e=0,t=1;for(;;){let r=this.readU8(),i=127&r;if(i>(Number.MAX_SAFE_INTEGER-e)/t)throw RangeError("Binary serialization varint exceeds Number.MAX_SAFE_INTEGER");if(e+=i*t,(128&r)==0)return e;if(t>Number.MAX_SAFE_INTEGER/128)throw RangeError("Binary serialization varint exceeds Number.MAX_SAFE_INTEGER");t*=128}}_readString(e){let t=this._pos;if(e>this._view.byteLength-t)throw RangeError("Unexpected end of hntrie binary serialization");let r=t+e;if(this._pos=r,null!==this._nodeBuffer){let e=!0;for(let i=t;i<r;i++)if(this._bytes[i]>127){e=!1;break}if(e)return this._nodeBuffer.toString("latin1",t,r)}return i.decode(this._bytes.subarray(t,r))}readKeyString(){return this._readString(this.readVarint())}readValueString(){let e=this.readVarint();return 0===e?null:this._readString(e-1)}},exports.ByteWriter=class{constructor(e=256){this._len=0,this._buf=new Uint8Array(e),this._view=new DataView(this._buf.buffer)}_ensure(e){if(this._len+e<=this._buf.byteLength)return;let t=2*this._buf.byteLength;for(;t<this._len+e;)t*=2;let r=new Uint8Array(t);r.set(this._buf.subarray(0,this._len)),this._buf=r,this._view=new DataView(this._buf.buffer)}writeU8(e){this._ensure(1),this._view.setUint8(this._len,e),this._len+=1}writeVarint(e){if(!Number.isSafeInteger(e)||e<0)throw RangeError("Binary serialization varint must be a non-negative safe integer");let t=e;for(;t>=128;)this.writeU8(t%128|128),t=Math.floor(t/128);this.writeU8(t)}_writeBytes(e){this._ensure(e.byteLength),this._buf.set(e,this._len),this._len+=e.byteLength}_writeString(e,t){let i=e.length,s=!0;for(let t=0;t<i;t++)if(e.charCodeAt(t)>127){s=!1;break}if(s){this.writeVarint(i+t),this._ensure(i);let r=this._buf,n=this._len;for(let t=0;t<i;t++)r[n+t]=e.charCodeAt(t);this._len=n+i;return}let l=function(e){if(0===e.length)return n.subarray(0,0);if(3*e.length<=765){let{written:t}=r.encodeInto(e,n);return n.subarray(0,t)}return r.encode(e)}(e);this.writeVarint(l.byteLength+t),this._writeBytes(l)}writeKeyString(e){this._writeString(e,0)}writeValueString(e){null===e?this.writeVarint(0):this._writeString(e,1)}toArrayBuffer(){return this._buf.buffer.slice(0,this._len)}},exports.RADIX_SEP="|",exports.labelsToHostname=function(t){let r=t.length;if(1===r){let r=t[0];return e.ID_TO_TLD.get(r)??r}let i=t[r-1];for(let e=r-2;e>0;e--)i+="."+t[e];let n=t[0];return i+("."+(e.ID_TO_TLD.get(n)??n))},exports.readBinaryHeader=function(e,t){if(72!==e.readU8()||78!==e.readU8()||1!==e.readU8()||e.readU8()!==t)throw TypeError("Invalid hntrie binary serialization format")},exports.splitHostname=function(e){let r=[];return t(e,e=>{r.push(e)}),r},exports.trieCleanup=function(e,t){let r=[e],i=e;for(let e=0,n=t.length;e<n;e++){let n=t[e],s=i.c?.get(n);if(!s)return;r.push(s),i=s}for(let e=r.length-1;e>0;e--){let t=r[e];if(0!==t.f||null!==t.c&&t.c.size>0)break;let i=r[e-1];i.c?.delete(t.k),i.c?.size===0&&(i.c=null)}},exports.trieCompressNode=function e(t){if(null!==t.c){for(let r of t.c.values())e(r);for(let[e,r]of t.c)if(null!==r.c&&1===r.c.size&&0===r.f){let i=r.c.values().next().value;i.k=r.k+"|"+i.k,t.c.set(e,i)}}},exports.trieExpandNode=function e(t,r,i){if(null===t.c)return;let n=[...t.c];for(let s=0,l=n.length;s<l;s++){let[l,o]=n[s],a=o.k.split("|"),u=a.length;if(u>1){let n=r(a[0]),s=n;for(let e=1;e<u;e++){let t=r(a[e]);e===u-1&&(t.c=o.c,t.f=o.f,i(t,o)),s.c=new Map,s.c.set(a[e],t),s=t}t.c.set(l,n),e(s,r,i)}else e(o,r,i)}},exports.trieHasCompressedKeys=function e(t){if(t.k.includes("|"))return!0;if(null!==t.c){for(let r of t.c.values())if(e(r))return!0}return!1},exports.trieWalkFind=function(e,t){let r=e,i=t.length;for(let e=0;e<i;e++){let i=r.c?.get(t[e]);if(!i)return null;r=i}return r},exports.trieWalkFindCompacted=function(e,t){let r=e,i=0,n=t.length;for(;i<n;){let e=r.c?.get(t[i]);if(!e)return null;let s=e.k.split("|"),l=s.length;for(let e=0;e<l;e++){if(i>=n||s[e]!==t[i])return null;i++}r=e}return r},exports.trieWalkFindH=function(e,r){let i=e;return t(r,e=>{let t=i.c?.get(e);if(!t)return!1;i=t})?i:null},exports.walkHostname=t,exports.writeBinaryHeader=function(e,t){e.writeU8(72),e.writeU8(78),e.writeU8(1),e.writeU8(t)};
|
package/dist/_utils.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TLD_TO_ID as e,ID_TO_TLD as t}from"./_tlds.mjs";let
|
|
1
|
+
import{TLD_TO_ID as e,ID_TO_TLD as t}from"./_tlds.mjs";let r="|";function i(t,r){let i=t.length;if(0===i)return!1!==r("");46===t.codePointAt(i-1)&&i--;let n=t.lastIndexOf(".",i-1),l=t.slice(n+1,i);if(!1===r(e.get(l)??l))return!1;for(;n>=0;)if(i=n,n=t.lastIndexOf(".",i-1),!1===r(t.slice(n+1,i)))return!1;return!0}function n(e){let t=[];return i(e,e=>{t.push(e)}),t}function l(e){let r=e.length;if(1===r){let r=e[0];return t.get(r)??r}let i=e[r-1];for(let t=r-2;t>0;t--)i+="."+e[t];let n=e[0];return i+("."+(t.get(n)??n))}function s(e,t){let r=e;return i(t,e=>{let t=r.c?.get(e);if(!t)return!1;r=t})?r:null}function f(e,t){let r=e,i=t.length;for(let e=0;e<i;e++){let i=r.c?.get(t[e]);if(!i)return null;r=i}return r}function a(e,t){let i=e,n=0,l=t.length;for(;n<l;){let e=i.c?.get(t[n]);if(!e)return null;let s=e.k.split(r),f=s.length;for(let e=0;e<f;e++){if(n>=l||s[e]!==t[n])return null;n++}i=e}return i}function u(e){if(e.k.includes(r))return!0;if(null!==e.c){for(let t of e.c.values())if(u(t))return!0}return!1}function o(e){if(null!==e.c){for(let t of e.c.values())o(t);for(let[t,i]of e.c)if(null!==i.c&&1===i.c.size&&0===i.f){let n=i.c.values().next().value;n.k=i.k+r+n.k,e.c.set(t,n)}}}function h(e,t,i){if(null===e.c)return;let n=[...e.c];for(let l=0,s=n.length;l<s;l++){let[s,f]=n[l],a=f.k.split(r),u=a.length;if(u>1){let r=t(a[0]),n=r;for(let e=1;e<u;e++){let r=t(a[e]);e===u-1&&(r.c=f.c,r.f=f.f,i(r,f)),n.c=new Map,n.c.set(a[e],r),n=r}e.c.set(s,r),h(n,t,i)}else h(f,t,i)}}function _(e,t){let r=[e],i=e;for(let e=0,n=t.length;e<n;e++){let n=t[e],l=i.c?.get(n);if(!l)return;r.push(l),i=l}for(let e=r.length-1;e>0;e--){let t=r[e];if(0!==t.f||null!==t.c&&t.c.size>0)break;let i=r[e-1];i.c?.delete(t.k),i.c?.size===0&&(i.c=null)}}let c=1,d=2,g=new TextEncoder,w=new TextDecoder(void 0,{fatal:!0}),b=new Uint8Array(765),y=String.fromCodePoint(66,117,102,102,101,114),p="u"<typeof window?globalThis[y]:void 0,E="function"==typeof p?.from?p.from.bind(p):null;class U{constructor(e=256){this._len=0,this._buf=new Uint8Array(e),this._view=new DataView(this._buf.buffer)}_ensure(e){if(this._len+e<=this._buf.byteLength)return;let t=2*this._buf.byteLength;for(;t<this._len+e;)t*=2;let r=new Uint8Array(t);r.set(this._buf.subarray(0,this._len)),this._buf=r,this._view=new DataView(this._buf.buffer)}writeU8(e){this._ensure(1),this._view.setUint8(this._len,e),this._len+=1}writeVarint(e){if(!Number.isSafeInteger(e)||e<0)throw RangeError("Binary serialization varint must be a non-negative safe integer");let t=e;for(;t>=128;)this.writeU8(t%128|128),t=Math.floor(t/128);this.writeU8(t)}_writeBytes(e){this._ensure(e.byteLength),this._buf.set(e,this._len),this._len+=e.byteLength}_writeString(e,t){let r=e.length,i=!0;for(let t=0;t<r;t++)if(e.charCodeAt(t)>127){i=!1;break}if(i){this.writeVarint(r+t),this._ensure(r);let i=this._buf,n=this._len;for(let t=0;t<r;t++)i[n+t]=e.charCodeAt(t);this._len=n+r;return}let n=function(e){if(0===e.length)return b.subarray(0,0);if(3*e.length<=765){let{written:t}=g.encodeInto(e,b);return b.subarray(0,t)}return g.encode(e)}(e);this.writeVarint(n.byteLength+t),this._writeBytes(n)}writeKeyString(e){this._writeString(e,0)}writeValueString(e){null===e?this.writeVarint(0):this._writeString(e,1)}toArrayBuffer(){return this._buf.buffer.slice(0,this._len)}}class m{constructor(e){this._pos=0,this._view=new DataView(e),this._bytes=new Uint8Array(e),this._nodeBuffer=null===E?null:E(e)}get done(){return this._pos>=this._view.byteLength}readU8(){let e=this._view.getUint8(this._pos);return this._pos+=1,e}readVarint(){let e=0,t=1;for(;;){let r=this.readU8(),i=127&r;if(i>(Number.MAX_SAFE_INTEGER-e)/t)throw RangeError("Binary serialization varint exceeds Number.MAX_SAFE_INTEGER");if(e+=i*t,(128&r)==0)return e;if(t>Number.MAX_SAFE_INTEGER/128)throw RangeError("Binary serialization varint exceeds Number.MAX_SAFE_INTEGER");t*=128}}_readString(e){let t=this._pos;if(e>this._view.byteLength-t)throw RangeError("Unexpected end of hntrie binary serialization");let r=t+e;if(this._pos=r,null!==this._nodeBuffer){let e=!0;for(let i=t;i<r;i++)if(this._bytes[i]>127){e=!1;break}if(e)return this._nodeBuffer.toString("latin1",t,r)}return w.decode(this._bytes.subarray(t,r))}readKeyString(){return this._readString(this.readVarint())}readValueString(){let e=this.readVarint();return 0===e?null:this._readString(e-1)}}function A(e,t){e.writeU8(72),e.writeU8(78),e.writeU8(1),e.writeU8(t)}function S(e,t){if(72!==e.readU8()||78!==e.readU8()||1!==e.readU8()||e.readU8()!==t)throw TypeError("Invalid hntrie binary serialization format")}export{d as BINARY_KIND_SMOL,c as BINARY_KIND_TRIE,m as ByteReader,U as ByteWriter,r as RADIX_SEP,l as labelsToHostname,S as readBinaryHeader,n as splitHostname,_ as trieCleanup,o as trieCompressNode,h as trieExpandNode,u as trieHasCompressedKeys,f as trieWalkFind,a as trieWalkFindCompacted,s as trieWalkFindH,i as walkHostname,A as writeBinaryHeader};
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,13 @@ declare class HostnameTrie<T = boolean> {
|
|
|
35
35
|
static deserialize<T = boolean>(this: void, data: string, valueFromString?: (s: string) => T): HostnameTrie<T>;
|
|
36
36
|
toJSON(): string;
|
|
37
37
|
static fromJSON<T = boolean>(this: void, data: string, valueFromString?: (s: string) => T): HostnameTrie<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Packed binary encoding of the same tree `serialize()` produces, returned as an
|
|
40
|
+
* `ArrayBuffer` suitable for `postMessage(buffer, [buffer])` — ownership transfers
|
|
41
|
+
* with no structured-clone copy, and no ASCII/separator overhead per field.
|
|
42
|
+
*/
|
|
43
|
+
serializeTransferable(valueToString?: (value: T) => string): ArrayBuffer;
|
|
44
|
+
static deserializeTransferable<T = boolean>(this: void, buffer: ArrayBuffer, valueFromString?: (s: string) => T): HostnameTrie<T>;
|
|
38
45
|
[Symbol.iterator](): Generator<[string, T, 'exact' | 'subdomain']>;
|
|
39
46
|
/** @internal */
|
|
40
47
|
private _expandIfCompacted;
|
|
@@ -47,6 +54,8 @@ declare class HostnameTrie<T = boolean> {
|
|
|
47
54
|
/** @internal */
|
|
48
55
|
private _serializeNode;
|
|
49
56
|
/** @internal */
|
|
57
|
+
private _serializeNodeBinary;
|
|
58
|
+
/** @internal */
|
|
50
59
|
private _iterateNode;
|
|
51
60
|
/** @internal */
|
|
52
61
|
private _collectEntries;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,"__esModule",{value:!0});var t,e=require("./_utils.js"),i=require("foxts/bitwise"),
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});var t,e=require("./_utils.js"),i=require("foxts/bitwise"),r=require("foxts/fast-string-array-join");let s="hntrie:1";function l(t){return{k:t,c:null,f:0,e:void 0,s:void 0}}function o(t,e){t.e=e.e,t.s=e.s}t=Symbol.iterator;class n{constructor(t){if(this._root=l(""),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 r=this._walkCreateH(t);return i.missingBit(r.f,1)&&this._size++,r.f=i.setBit(r.f,1),r.e=e,this}addSubdomain(t,e=!0){this._expandIfCompacted();let r=this._walkCreateH(t);return i.missingBit(r.f,2)&&this._size++,r.f=i.setBit(r.f,2),r.s=e,this}remove(t){this._expandIfCompacted();let r=e.splitHostname(t),s=e.trieWalkFind(this._root,r);return!(!s||i.missingBit(s.f,1))&&(s.f=i.deleteBit(s.f,1),s.e=void 0,this._size--,e.trieCleanup(this._root,r),!0)}removeSubdomain(t){this._expandIfCompacted();let r=e.splitHostname(t),s=e.trieWalkFind(this._root,r);return!(!s||i.missingBit(s.f,2))&&(s.f=i.deleteBit(s.f,2),s.s=void 0,this._size--,e.trieCleanup(this._root,r),!0)}delete(t){return 46===t.codePointAt(0)?this.removeSubdomain(t.slice(1)):this.remove(t)}has(t){if(this._compacted){let r=e.splitHostname(t);return i.getBit(e.trieWalkFindCompacted(this._root,r)?.f??0,1)}return i.getBit(e.trieWalkFindH(this._root,t)?.f??0,1)}hasSubdomain(t){if(this._compacted){let r=e.splitHostname(t);return i.getBit(e.trieWalkFindCompacted(this._root,r)?.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 r=this._compacted;this._expandIfCompacted();let s=46===t.codePointAt(0),l=s?t.slice(1):t,o=e.splitHostname(l),n=e.trieWalkFind(this._root,o),a=[];if(!n)return r&&this.compact(),a;if(s){if(i.getBit(n.f,2)&&a.push("."+l),null!==n.c)for(let t of n.c.values())this._collectEntries(t,o,a)}else this._collectEntries(n,o.slice(0,-1),a);return r&&this.compact(),a}dump(t){this._walkDump(this._root,[],t)}compact(){return this._compacted||(e.trieCompressNode(this._root),this._compacted=!0),this}serialize(t){let e=[s];return this._serializeNode(this._root,e,t),r.fastStringArrayJoin(e,"\n")}static deserialize(t,r){let o=new n,a=t.split("\n");if(a[0]!==s)throw Error("Invalid hntrie serialization format");let f=0,d=[[o._root,-1]],c=a.length;for(let t=1;t<c;t++){let s=a[t];if(0===s.length)continue;let o=s.split(" "),n=Number.parseInt(o[0],36),c=o[1],h=Number.parseInt(o[2],36),u=o[3]||"",p=o[4]||"",_=l(c);for(_.f=h,i.getBit(h,1)&&(_.e=!u||(r?r(u):JSON.parse(u)),f++),i.getBit(h,2)&&(_.s=!p||(r?r(p):JSON.parse(p)),f++);d.length>1&&d[d.length-1][1]>=n;)d.pop();let m=d[d.length-1][0];null===m.c&&(m.c=new Map);let g=c.includes(e.RADIX_SEP)?c.slice(0,c.indexOf(e.RADIX_SEP)):c;m.c.set(g,_),d.push([_,n])}return o._size=f,o._compacted=e.trieHasCompressedKeys(o._root),o}toJSON(){return this.serialize()}static fromJSON(t,e){return n.deserialize(t,e)}serializeTransferable(t){let i=new e.ByteWriter;return e.writeBinaryHeader(i,e.BINARY_KIND_TRIE),this._serializeNodeBinary(this._root,i,t,-1),i.toArrayBuffer()}static deserializeTransferable(t,r){let s=new n,o=new e.ByteReader(t);e.readBinaryHeader(o,e.BINARY_KIND_TRIE);let a=0,f=[[s._root,-1]];for(;!o.done;){let t=o.readVarint(),s=o.readU8();if((-4&s)!=0)throw TypeError("Invalid flags in hntrie binary serialization");let n=o.readKeyString();for(;f.length>1&&f[f.length-1][1]>=t;)f.pop();let[d,c]=f[f.length-1];if(c!==t-1)throw TypeError("Invalid node depth in hntrie binary serialization");let h=n.includes(e.RADIX_SEP)?n.slice(0,n.indexOf(e.RADIX_SEP)):n;if(d.c?.has(h))throw TypeError("Duplicate node key in hntrie binary serialization");let u=l(n);if(u.f=s,i.getBit(s,1)){let t=o.readValueString();u.e=null===t||(r?r(t):JSON.parse(t)),a++}if(i.getBit(s,2)){let t=o.readValueString();u.s=null===t||(r?r(t):JSON.parse(t)),a++}null===d.c&&(d.c=new Map),d.c.set(h,u),f.push([u,t])}return s._size=a,s._compacted=e.trieHasCompressedKeys(s._root),s}*[t](){yield*this._iterateNode(this._root,[])}_expandIfCompacted(){this._compacted&&(e.trieExpandNode(this._root,l,o),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=l(t),i.c.set(t,e)),i=e}),i}_matchUnfrozenH(t){let r=this._root,s=null;return e.walkHostname(t,t=>{let e=r.c?.get(t);if(!e)return!1;r=e,i.getBit(r.f,2)&&(s=r.s)})&&i.getBit(r.f,1)?r.e:s}_matchCompacted(t){let r=this._root,s=null,l=0,o=t.length;for(;l<o;){let n=r.c?.get(t[l]);if(!n)return s;let a=n.k.split(e.RADIX_SEP),f=a.length;for(let e=0;e<f;e++){if(l>=o||a[e]!==t[l])return s;l++}r=n,i.getBit(r.f,2)&&(s=r.s)}return i.getBit(r.f,1)?r.e:s}_serializeNode(t,e,r,s=-1){if(s>=0){let l="",o="";i.getBit(t.f,1)&&!0!==t.e&&(l=r?r(t.e):JSON.stringify(t.e)),i.getBit(t.f,2)&&!0!==t.s&&(o=r?r(t.s):JSON.stringify(t.s));let n=s.toString(36)+" "+t.k+" "+t.f.toString(36);(l||o)&&(n+=" "+l,o&&(n+=" "+o)),e.push(n)}if(null!==t.c)for(let i of t.c.values())this._serializeNode(i,e,r,s+1)}_serializeNodeBinary(t,e,r,s){if(s>=0&&(e.writeVarint(s),e.writeU8(t.f),e.writeKeyString(t.k),i.getBit(t.f,1)&&e.writeValueString(!0===t.e?null:r?r(t.e):JSON.stringify(t.e)),i.getBit(t.f,2)&&e.writeValueString(!0===t.s?null:r?r(t.s):JSON.stringify(t.s))),null!==t.c)for(let i of t.c.values())this._serializeNodeBinary(i,e,r,s+1)}*_iterateNode(t,r){let s=""===t.k?[]:t.k.split(e.RADIX_SEP),l=s.length;for(let t=0;t<l;t++)r.push(s[t]);if(i.getBit(t.f,1)&&(yield[e.labelsToHostname(r),t.e,"exact"]),i.getBit(t.f,2)&&(yield[e.labelsToHostname(r),t.s,"subdomain"]),null!==t.c)for(let e of t.c.values())yield*this._iterateNode(e,r);for(let t=0;t<l;t++)r.pop()}_collectEntries(t,r,s){let l=""===t.k?[]:t.k.split(e.RADIX_SEP),o=l.length;for(let t=0;t<o;t++)r.push(l[t]);if(i.getBit(t.f,2)&&s.push("."+e.labelsToHostname(r)),i.getBit(t.f,1)&&s.push(e.labelsToHostname(r)),null!==t.c)for(let e of t.c.values())this._collectEntries(e,r,s);for(let t=0;t<o;t++)r.pop()}_walkDump(t,r,s){let l=""===t.k?[]:t.k.split(e.RADIX_SEP),o=l.length;for(let t=0;t<o;t++)r.push(l[t]);if(i.getBit(t.f,2)&&s(e.labelsToHostname(r),!0,t.s),i.getBit(t.f,1)&&s(e.labelsToHostname(r),!1,t.e),null!==t.c)for(let e of t.c.values())this._walkDump(e,r,s);for(let t=0;t<o;t++)r.pop()}}exports.HostnameTrie=n;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +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,
|
|
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,trieHasCompressedKeys as a,ByteWriter as f,writeBinaryHeader as h,BINARY_KIND_TRIE as c,ByteReader as d,readBinaryHeader as u,trieExpandNode as p,walkHostname as _,labelsToHostname as m}from"./_utils.mjs";import{missingBit as g,setBit as z,deleteBit as S,getBit as w}from"foxts/bitwise";import{fastStringArrayJoin as y}from"foxts/fast-string-array-join";let N="hntrie:1";function v(t){return{k:t,c:null,f:0,e:void 0,s:void 0}}function k(t,e){t.e=e.e,t.s=e.s}t=Symbol.iterator;class b{constructor(t){if(this._root=v(""),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 g(i.f,1)&&this._size++,i.f=z(i.f,1),i.e=e,this}addSubdomain(t,e=!0){this._expandIfCompacted();let i=this._walkCreateH(t);return g(i.f,2)&&this._size++,i.f=z(i.f,2),i.s=e,this}remove(t){this._expandIfCompacted();let o=e(t),s=i(this._root,o);return!(!s||g(s.f,1))&&(s.f=S(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||g(s.f,2))&&(s.f=S(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 w(o(this._root,i)?.f??0,1)}return w(s(this._root,t)?.f??0,1)}hasSubdomain(t){if(this._compacted){let i=e(t);return w(o(this._root,i)?.f??0,2)}return w(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=this._compacted;this._expandIfCompacted();let o=46===t.codePointAt(0),s=o?t.slice(1):t,l=e(s),n=i(this._root,l),a=[];if(!n)return r&&this.compact(),a;if(o){if(w(n.f,2)&&a.push("."+s),null!==n.c)for(let t of n.c.values())this._collectEntries(t,l,a)}else this._collectEntries(n,l.slice(0,-1),a);return r&&this.compact(),a}dump(t){this._walkDump(this._root,[],t)}compact(){return this._compacted||(l(this._root),this._compacted=!0),this}serialize(t){let e=[N];return this._serializeNode(this._root,e,t),y(e,"\n")}static deserialize(t,e){let i=new b,r=t.split("\n");if(r[0]!==N)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(" "),a=Number.parseInt(l[0],36),f=l[1],h=Number.parseInt(l[2],36),c=l[3]||"",d=l[4]||"",u=v(f);for(u.f=h,w(h,1)&&(u.e=!c||(e?e(c):JSON.parse(c)),o++),w(h,2)&&(u.s=!d||(e?e(d):JSON.parse(d)),o++);s.length>1&&s[s.length-1][1]>=a;)s.pop();let p=s[s.length-1][0];null===p.c&&(p.c=new Map);let _=f.includes(n)?f.slice(0,f.indexOf(n)):f;p.c.set(_,u),s.push([u,a])}return i._size=o,i._compacted=a(i._root),i}toJSON(){return this.serialize()}static fromJSON(t,e){return b.deserialize(t,e)}serializeTransferable(t){let e=new f;return h(e,c),this._serializeNodeBinary(this._root,e,t,-1),e.toArrayBuffer()}static deserializeTransferable(t,e){let i=new b,r=new d(t);u(r,c);let o=0,s=[[i._root,-1]];for(;!r.done;){let t=r.readVarint(),i=r.readU8();if((-4&i)!=0)throw TypeError("Invalid flags in hntrie binary serialization");let l=r.readKeyString();for(;s.length>1&&s[s.length-1][1]>=t;)s.pop();let[a,f]=s[s.length-1];if(f!==t-1)throw TypeError("Invalid node depth in hntrie binary serialization");let h=l.includes(n)?l.slice(0,l.indexOf(n)):l;if(a.c?.has(h))throw TypeError("Duplicate node key in hntrie binary serialization");let c=v(l);if(c.f=i,w(i,1)){let t=r.readValueString();c.e=null===t||(e?e(t):JSON.parse(t)),o++}if(w(i,2)){let t=r.readValueString();c.s=null===t||(e?e(t):JSON.parse(t)),o++}null===a.c&&(a.c=new Map),a.c.set(h,c),s.push([c,t])}return i._size=o,i._compacted=a(i._root),i}*[t](){yield*this._iterateNode(this._root,[])}_expandIfCompacted(){this._compacted&&(p(this._root,v,k),this._compacted=!1)}_walkCreateH(t){let e=this._root;return _(t,t=>{null===e.c&&(e.c=new Map);let i=e.c.get(t);i||(i=v(t),e.c.set(t,i)),e=i}),e}_matchUnfrozenH(t){let e=this._root,i=null;return _(t,t=>{let r=e.c?.get(t);if(!r)return!1;w((e=r).f,2)&&(i=e.s)})&&w(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),a=l.length;for(let e=0;e<a;e++){if(r>=o||l[e]!==t[r])return i;r++}w((e=s).f,2)&&(i=e.s)}return w(e.f,1)?e.e:i}_serializeNode(t,e,i,r=-1){if(r>=0){let o="",s="";w(t.f,1)&&!0!==t.e&&(o=i?i(t.e):JSON.stringify(t.e)),w(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)}_serializeNodeBinary(t,e,i,r){if(r>=0&&(e.writeVarint(r),e.writeU8(t.f),e.writeKeyString(t.k),w(t.f,1)&&e.writeValueString(!0===t.e?null:i?i(t.e):JSON.stringify(t.e)),w(t.f,2)&&e.writeValueString(!0===t.s?null:i?i(t.s):JSON.stringify(t.s))),null!==t.c)for(let o of t.c.values())this._serializeNodeBinary(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(w(t.f,1)&&(yield[m(e),t.e,"exact"]),w(t.f,2)&&(yield[m(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(w(t.f,2)&&i.push("."+m(e)),w(t.f,1)&&i.push(m(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(w(t.f,2)&&i(m(e),!0,t.s),w(t.f,1)&&i(m(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{b as HostnameTrie};
|
package/dist/smol.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ declare class HostnameSmolTrie {
|
|
|
27
27
|
compact(): this;
|
|
28
28
|
dump(cb: (hostname: string, includeSubdomain: boolean) => void): void;
|
|
29
29
|
static load(this: void, entries: string[]): HostnameSmolTrie;
|
|
30
|
+
/**
|
|
31
|
+
* Packed binary encoding of the trie (same tree shape `dump()` walks), returned as
|
|
32
|
+
* an `ArrayBuffer` suitable for `postMessage(buffer, [buffer])` — ownership transfers
|
|
33
|
+
* with no structured-clone copy, and no ASCII/separator overhead per field.
|
|
34
|
+
*/
|
|
35
|
+
serializeTransferable(): ArrayBuffer;
|
|
36
|
+
static deserializeTransferable(this: void, buffer: ArrayBuffer): HostnameSmolTrie;
|
|
30
37
|
/** @internal */
|
|
31
38
|
private _expandIfCompacted;
|
|
32
39
|
/** @internal Walk hostname, creating nodes. Returns null if covered by ancestor subdomain. */
|
|
@@ -39,6 +46,8 @@ declare class HostnameSmolTrie {
|
|
|
39
46
|
private _collectEntries;
|
|
40
47
|
/** @internal */
|
|
41
48
|
private _walkDump;
|
|
49
|
+
/** @internal */
|
|
50
|
+
private _serializeNodeBinary;
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
export { HostnameSmolTrie };
|
package/dist/smol.js
CHANGED
|
@@ -1 +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
|
|
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 r=require("foxts/noop").noop;exports.HostnameSmolTrie=class o{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 r=t.splitHostname(i),o=t.trieWalkFind(this._root,r);return!(!o||e.missingBit(o.f,1))&&(o.f=e.deleteBit(o.f,1),t.trieCleanup(this._root,r),!0)}removeSubdomain(i){this._expandIfCompacted();let r=t.splitHostname(i),o=t.trieWalkFind(this._root,r);return!(!o||e.missingBit(o.f,2))&&(o.f=e.deleteBit(o.f,2),t.trieCleanup(this._root,r),!0)}delete(t){return 46===t.codePointAt(0)?this.removeSubdomain(t.slice(1)):this.remove(t)}whitelist(i){this._expandIfCompacted();let r=46===i.codePointAt(0),o=r?i.slice(1):i,l=t.splitHostname(o),s=t.trieWalkFind(this._root,l);s&&(r?(s.f=0,s.c=null):(s.f=e.deleteBit(s.f,1),s.f=e.deleteBit(s.f,2)),t.trieCleanup(this._root,l))}has(i){if(this._compacted){let r=t.splitHostname(i);return e.getBit(t.trieWalkFindCompacted(this._root,r)?.f??0,1)}return e.getBit(t.trieWalkFindH(this._root,i)?.f??0,1)}hasSubdomain(i){if(this._compacted){let r=t.splitHostname(i);return e.getBit(t.trieWalkFindCompacted(this._root,r)?.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 r=this._compacted;this._expandIfCompacted();let o=46===i.codePointAt(0),l=o?i.slice(1):i,s=t.splitHostname(l),n=t.trieWalkFind(this._root,s),a=[];if(!n)return r&&this.compact(),a;if(o){if(e.getBit(n.f,2)&&a.push("."+l),null!==n.c)for(let t of n.c.values())this._collectEntries(t,s,a)}else this._collectEntries(n,s.slice(0,-1),a);return r&&this.compact(),a}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 o,i=t.length;for(let r=0;r<i;r++){let i=t[r];46===i.codePointAt(0)?e.addSubdomain(i.slice(1)):e.add(i)}return e}serializeTransferable(){let e=new t.ByteWriter;return t.writeBinaryHeader(e,t.BINARY_KIND_SMOL),this._serializeNodeBinary(this._root,e,-1),e.toArrayBuffer()}static deserializeTransferable(r){let l=new o,s=new t.ByteReader(r);t.readBinaryHeader(s,t.BINARY_KIND_SMOL);let n=[[l._root,-1]];for(;!s.done;){let r=s.readVarint(),o=s.readU8();if((-4&o)!=0||3===o)throw TypeError("Invalid flags in hntrie binary serialization");let l=s.readKeyString();for(;n.length>1&&n[n.length-1][1]>=r;)n.pop();let[a,d]=n[n.length-1];if(d!==r-1||e.getBit(a.f,2))throw TypeError("Invalid node depth in hntrie binary serialization");let c=l.includes(t.RADIX_SEP)?l.slice(0,l.indexOf(t.RADIX_SEP)):l;if(a.c?.has(c))throw TypeError("Duplicate node key in hntrie binary serialization");let f=i(l);f.f=o,null===a.c&&(a.c=new Map),a.c.set(c,f),n.push([f,r])}return l._compacted=t.trieHasCompressedKeys(l._root),l}_expandIfCompacted(){this._compacted&&(t.trieExpandNode(this._root,i,r),this._compacted=!1)}_walkCreateOrCovered(r){let o=this._root;return t.walkHostname(r,t=>{null===o.c&&(o.c=new Map);let r=o.c.get(t);if(r||(r=i(t),o.c.set(t,r)),o=r,e.getBit(o.f,2))return!1})?o:null}_matchUnfrozenH(i){let r=this._root;return t.walkHostname(i,t=>{let i=r.c?.get(t);return!!i&&(r=i,!e.getBit(r.f,2)&&void 0)})?0!==r.f:e.getBit(r.f,2)}_matchCompacted(i){let r=this._root,o=0,l=i.length;for(;o<l;){let s=r.c?.get(i[o]);if(!s)return!1;let n=s.k.split(t.RADIX_SEP),a=n.length;for(let t=0;t<a;t++){if(o>=l||n[t]!==i[o])return!1;o++}if(r=s,e.getBit(r.f,2))return!0}return 0!==r.f}_collectEntries(i,r,o){let l=""===i.k?[]:i.k.split(t.RADIX_SEP),s=l.length;for(let t=0;t<s;t++)r.push(l[t]);if(e.getBit(i.f,2)?o.push("."+t.labelsToHostname(r)):e.getBit(i.f,1)&&o.push(t.labelsToHostname(r)),null!==i.c&&e.missingBit(i.f,2))for(let t of i.c.values())this._collectEntries(t,r,o);for(let t=0;t<s;t++)r.pop()}_walkDump(i,r,o){let l=""===i.k?[]:i.k.split(t.RADIX_SEP),s=l.length;for(let t=0;t<s;t++)r.push(l[t]);if(e.getBit(i.f,2)?o(t.labelsToHostname(r),!0):e.getBit(i.f,1)&&o(t.labelsToHostname(r),!1),null!==i.c&&e.missingBit(i.f,2))for(let t of i.c.values())this._walkDump(t,r,o);for(let t=0;t<s;t++)r.pop()}_serializeNodeBinary(t,e,i){if(i>=0&&(e.writeVarint(i),e.writeU8(t.f),e.writeKeyString(t.k)),null!==t.c)for(let r of t.c.values())this._serializeNodeBinary(r,e,i+1)}};
|
package/dist/smol.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitHostname as t,trieWalkFind as e,trieCleanup as
|
|
1
|
+
import{splitHostname as t,trieWalkFind as e,trieCleanup as r,trieWalkFindCompacted as i,trieWalkFindH as o,trieCompressNode as l,ByteWriter as n,writeBinaryHeader as s,BINARY_KIND_SMOL as a,ByteReader as f,readBinaryHeader as c,RADIX_SEP as h,trieHasCompressedKeys as d,trieExpandNode as u,walkHostname as p,labelsToHostname as _}from"./_utils.mjs";import{setBit as m,missingBit as w,deleteBit as g,getBit as C}from"foxts/bitwise";import{noop as k}from"foxts/noop";function b(t){return{k:t,c:null,f:0}}class v{constructor(t){if(this._root=b(""),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=m(e.f,1)),this}addSubdomain(t){this._expandIfCompacted();let e=this._walkCreateOrCovered(t);return null===e||w(e.f,2)&&(e.c=null,e.f=m(e.f,2),e.f=g(e.f,1)),this}remove(i){this._expandIfCompacted();let o=t(i),l=e(this._root,o);return!(!l||w(l.f,1))&&(l.f=g(l.f,1),r(this._root,o),!0)}removeSubdomain(i){this._expandIfCompacted();let o=t(i),l=e(this._root,o);return!(!l||w(l.f,2))&&(l.f=g(l.f,2),r(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),l=t(o?i.slice(1):i),n=e(this._root,l);n&&(o?(n.f=0,n.c=null):(n.f=g(n.f,1),n.f=g(n.f,2)),r(this._root,l))}has(e){if(this._compacted){let r=t(e);return C(i(this._root,r)?.f??0,1)}return C(o(this._root,e)?.f??0,1)}hasSubdomain(e){if(this._compacted){let r=t(e);return C(i(this._root,r)?.f??0,2)}return C(o(this._root,e)?.f??0,2)}match(e){if(this._compacted){let r=t(e);return this._matchCompacted(r)}return this._matchUnfrozenH(e)}contains(t){return this.match(t)}find(r){let i=this._compacted;this._expandIfCompacted();let o=46===r.codePointAt(0),l=o?r.slice(1):r,n=t(l),s=e(this._root,n),a=[];if(!s)return i&&this.compact(),a;if(o){if(C(s.f,2)&&a.push("."+l),null!==s.c)for(let t of s.c.values())this._collectEntries(t,n,a)}else this._collectEntries(s,n.slice(0,-1),a);return i&&this.compact(),a}compact(){return this._compacted||(l(this._root),this._compacted=!0),this}dump(t){this._walkDump(this._root,[],t)}static load(t){let e=new v,r=t.length;for(let i=0;i<r;i++){let r=t[i];46===r.codePointAt(0)?e.addSubdomain(r.slice(1)):e.add(r)}return e}serializeTransferable(){let t=new n;return s(t,a),this._serializeNodeBinary(this._root,t,-1),t.toArrayBuffer()}static deserializeTransferable(t){let e=new v,r=new f(t);c(r,a);let i=[[e._root,-1]];for(;!r.done;){let t=r.readVarint(),e=r.readU8();if((-4&e)!=0||3===e)throw TypeError("Invalid flags in hntrie binary serialization");let o=r.readKeyString();for(;i.length>1&&i[i.length-1][1]>=t;)i.pop();let[l,n]=i[i.length-1];if(n!==t-1||C(l.f,2))throw TypeError("Invalid node depth in hntrie binary serialization");let s=o.includes(h)?o.slice(0,o.indexOf(h)):o;if(l.c?.has(s))throw TypeError("Duplicate node key in hntrie binary serialization");let a=b(o);a.f=e,null===l.c&&(l.c=new Map),l.c.set(s,a),i.push([a,t])}return e._compacted=d(e._root),e}_expandIfCompacted(){this._compacted&&(u(this._root,b,k),this._compacted=!1)}_walkCreateOrCovered(t){let e=this._root;return p(t,t=>{null===e.c&&(e.c=new Map);let r=e.c.get(t);if(r||(r=b(t),e.c.set(t,r)),C((e=r).f,2))return!1})?e:null}_matchUnfrozenH(t){let e=this._root;return p(t,t=>{let r=e.c?.get(t);if(!r||C((e=r).f,2))return!1})?0!==e.f:C(e.f,2)}_matchCompacted(t){let e=this._root,r=0,i=t.length;for(;r<i;){let o=e.c?.get(t[r]);if(!o)return!1;let l=o.k.split(h),n=l.length;for(let e=0;e<n;e++){if(r>=i||l[e]!==t[r])return!1;r++}if(C((e=o).f,2))return!0}return 0!==e.f}_collectEntries(t,e,r){let i=""===t.k?[]:t.k.split(h),o=i.length;for(let t=0;t<o;t++)e.push(i[t]);if(C(t.f,2)?r.push("."+_(e)):C(t.f,1)&&r.push(_(e)),null!==t.c&&w(t.f,2))for(let i of t.c.values())this._collectEntries(i,e,r);for(let t=0;t<o;t++)e.pop()}_walkDump(t,e,r){let i=""===t.k?[]:t.k.split(h),o=i.length;for(let t=0;t<o;t++)e.push(i[t]);if(C(t.f,2)?r(_(e),!0):C(t.f,1)&&r(_(e),!1),null!==t.c&&w(t.f,2))for(let i of t.c.values())this._walkDump(i,e,r);for(let t=0;t<o;t++)e.pop()}_serializeNodeBinary(t,e,r){if(r>=0&&(e.writeVarint(r),e.writeU8(t.f),e.writeKeyString(t.k)),null!==t.c)for(let i of t.c.values())this._serializeNodeBinary(i,e,r+1)}}export{v as HostnameSmolTrie};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hntrie",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "The extremely fast Trie implementation optimized for Hostname.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,19 +35,22 @@
|
|
|
35
35
|
"author": "SukkaW <https://skk.moe>",
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"foxts": "^5.
|
|
38
|
+
"foxts": "^5.8.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
42
|
-
"@
|
|
43
|
-
"@swc/
|
|
42
|
+
"@mitata/counters": "^0.0.8",
|
|
43
|
+
"@swc-node/register": "^1.12.1",
|
|
44
|
+
"@swc/core": "^1.15.47",
|
|
44
45
|
"@types/mocha": "^10.0.10",
|
|
46
|
+
"@types/node": "^26.1.2",
|
|
45
47
|
"bumpp": "^10.4.1",
|
|
46
|
-
"bunchee": "^6.
|
|
48
|
+
"bunchee": "^6.12.2",
|
|
47
49
|
"earl": "^2.0.0",
|
|
48
|
-
"eslint": "^10.
|
|
49
|
-
"eslint-config-sukka": "^8.
|
|
50
|
-
"eslint-formatter-sukka": "^8.
|
|
50
|
+
"eslint": "^10.8.0",
|
|
51
|
+
"eslint-config-sukka": "^8.14.2",
|
|
52
|
+
"eslint-formatter-sukka": "^8.14.2",
|
|
53
|
+
"mitata": "^1.0.34",
|
|
51
54
|
"mocha": "^11.7.6",
|
|
52
55
|
"nyc": "^18.0.0",
|
|
53
56
|
"typescript": "^6.0.3"
|