rusteerio 0.0.0-stage → 0.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.
Files changed (206) hide show
  1. package/CONTRIBUTING.md +73 -0
  2. package/Cargo.lock +1051 -0
  3. package/Cargo.toml +36 -0
  4. package/LICENSE +21 -0
  5. package/README.md +252 -2
  6. package/RELEASING.md +138 -0
  7. package/THIRD_PARTY_NOTICES.md +7443 -0
  8. package/build.rs +3 -0
  9. package/dist/chunk-DKULX6VO.mjs +3185 -0
  10. package/dist/chunk-DKULX6VO.mjs.map +1 -0
  11. package/dist/chunk-OHPGEY3E.mjs +32 -0
  12. package/dist/chunk-OHPGEY3E.mjs.map +1 -0
  13. package/dist/index.cjs +3230 -0
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/index.d.mts +113 -0
  16. package/dist/index.d.ts +113 -0
  17. package/dist/index.mjs +38 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/slim.cjs +2441 -0
  20. package/dist/slim.cjs.map +1 -0
  21. package/dist/slim.d.mts +11 -0
  22. package/dist/slim.d.ts +11 -0
  23. package/dist/slim.mjs +19 -0
  24. package/dist/slim.mjs.map +1 -0
  25. package/dist/types-BP6TpxE5.d.mts +532 -0
  26. package/dist/types-BP6TpxE5.d.ts +532 -0
  27. package/dist/utils.cjs +61 -0
  28. package/dist/utils.cjs.map +1 -0
  29. package/dist/utils.d.mts +13 -0
  30. package/dist/utils.d.ts +13 -0
  31. package/dist/utils.mjs +17 -0
  32. package/dist/utils.mjs.map +1 -0
  33. package/native/src/arena.rs +1781 -0
  34. package/native/src/attributes.rs +923 -0
  35. package/native/src/codec.rs +172 -0
  36. package/native/src/diagnostics.rs +1249 -0
  37. package/native/src/extraction.rs +226 -0
  38. package/native/src/gc.rs +166 -0
  39. package/native/src/hook_sink.rs +727 -0
  40. package/native/src/hook_stream.rs +513 -0
  41. package/native/src/lib.rs +2095 -0
  42. package/native/src/location.rs +392 -0
  43. package/native/src/runtime.rs +189 -0
  44. package/native/src/selector.rs +1287 -0
  45. package/native/src/sink.rs +261 -0
  46. package/native/src/stream.rs +334 -0
  47. package/native/src/tokenizer.rs +355 -0
  48. package/native/src/tracker.rs +232 -0
  49. package/native/vendor/README.md +25 -0
  50. package/native/vendor/html5ever-0.35.0/.cargo_vcs_info.json +6 -0
  51. package/native/vendor/html5ever-0.35.0/Cargo.lock +828 -0
  52. package/native/vendor/html5ever-0.35.0/Cargo.toml +85 -0
  53. package/native/vendor/html5ever-0.35.0/LICENSE-APACHE +201 -0
  54. package/native/vendor/html5ever-0.35.0/LICENSE-MIT +25 -0
  55. package/native/vendor/html5ever-0.35.0/README.md +60 -0
  56. package/native/vendor/html5ever-0.35.0/benches/html5ever.rs +86 -0
  57. package/native/vendor/html5ever-0.35.0/data/bench/lipsum-zh.html +19 -0
  58. package/native/vendor/html5ever-0.35.0/data/bench/lipsum.html +40 -0
  59. package/native/vendor/html5ever-0.35.0/data/bench/medium-fragment.html +24 -0
  60. package/native/vendor/html5ever-0.35.0/data/bench/small-fragment.html +7 -0
  61. package/native/vendor/html5ever-0.35.0/data/bench/strong.html +1 -0
  62. package/native/vendor/html5ever-0.35.0/data/bench/tiny-fragment.html +1 -0
  63. package/native/vendor/html5ever-0.35.0/examples/arena.rs +356 -0
  64. package/native/vendor/html5ever-0.35.0/examples/capi/tokenize.c +74 -0
  65. package/native/vendor/html5ever-0.35.0/examples/noop-tokenize.rs +47 -0
  66. package/native/vendor/html5ever-0.35.0/examples/noop-tree-builder.rs +132 -0
  67. package/native/vendor/html5ever-0.35.0/examples/print-tree-actions.rs +185 -0
  68. package/native/vendor/html5ever-0.35.0/examples/tokenize.rs +111 -0
  69. package/native/vendor/html5ever-0.35.0/src/driver.rs +148 -0
  70. package/native/vendor/html5ever-0.35.0/src/lib.rs +30 -0
  71. package/native/vendor/html5ever-0.35.0/src/macros.rs +34 -0
  72. package/native/vendor/html5ever-0.35.0/src/serialize/mod.rs +255 -0
  73. package/native/vendor/html5ever-0.35.0/src/tokenizer/char_ref/mod.rs +451 -0
  74. package/native/vendor/html5ever-0.35.0/src/tokenizer/interface.rs +99 -0
  75. package/native/vendor/html5ever-0.35.0/src/tokenizer/mod.rs +2305 -0
  76. package/native/vendor/html5ever-0.35.0/src/tokenizer/states.rs +97 -0
  77. package/native/vendor/html5ever-0.35.0/src/tree_builder/data.rs +170 -0
  78. package/native/vendor/html5ever-0.35.0/src/tree_builder/mod.rs +1848 -0
  79. package/native/vendor/html5ever-0.35.0/src/tree_builder/rules.rs +1494 -0
  80. package/native/vendor/html5ever-0.35.0/src/tree_builder/tag_sets.rs +114 -0
  81. package/native/vendor/html5ever-0.35.0/src/tree_builder/types.rs +91 -0
  82. package/native/vendor/html5ever-0.35.0/src/util/str.rs +52 -0
  83. package/native/vendor/html5gum-0.8.4/Cargo.lock +1006 -0
  84. package/native/vendor/html5gum-0.8.4/Cargo.toml +109 -0
  85. package/native/vendor/html5gum-0.8.4/LICENSE +19 -0
  86. package/native/vendor/html5gum-0.8.4/README.md +110 -0
  87. package/native/vendor/html5gum-0.8.4/benches/files/0050.html +2131 -0
  88. package/native/vendor/html5gum-0.8.4/benches/files/6D30.html +1004 -0
  89. package/native/vendor/html5gum-0.8.4/benches/files.rs +32 -0
  90. package/native/vendor/html5gum-0.8.4/benches/patterns.rs +31 -0
  91. package/native/vendor/html5gum-0.8.4/src/arrayvec.rs +29 -0
  92. package/native/vendor/html5gum-0.8.4/src/char_validator.rs +134 -0
  93. package/native/vendor/html5gum-0.8.4/src/emitters/callback.rs +676 -0
  94. package/native/vendor/html5gum-0.8.4/src/emitters/default.rs +207 -0
  95. package/native/vendor/html5gum-0.8.4/src/emitters/emitter.rs +344 -0
  96. package/native/vendor/html5gum-0.8.4/src/emitters/html5ever.rs +306 -0
  97. package/native/vendor/html5gum-0.8.4/src/emitters/mod.rs +25 -0
  98. package/native/vendor/html5gum-0.8.4/src/entities.rs +3342 -0
  99. package/native/vendor/html5gum-0.8.4/src/error.rs +96 -0
  100. package/native/vendor/html5gum-0.8.4/src/htmlstring.rs +130 -0
  101. package/native/vendor/html5gum-0.8.4/src/lib.rs +66 -0
  102. package/native/vendor/html5gum-0.8.4/src/machine.rs +2136 -0
  103. package/native/vendor/html5gum-0.8.4/src/machine_helper.rs +277 -0
  104. package/native/vendor/html5gum-0.8.4/src/read_helper.rs +244 -0
  105. package/native/vendor/html5gum-0.8.4/src/reader.rs +440 -0
  106. package/native/vendor/html5gum-0.8.4/src/span.rs +98 -0
  107. package/native/vendor/html5gum-0.8.4/src/state.rs +16 -0
  108. package/native/vendor/html5gum-0.8.4/src/testutils.rs +71 -0
  109. package/native/vendor/html5gum-0.8.4/src/tokenizer.rs +189 -0
  110. package/native/vendor/html5gum-0.8.4/src/utils.rs +88 -0
  111. package/native/vendor/markup5ever-0.35.0/.cargo_vcs_info.json +6 -0
  112. package/native/vendor/markup5ever-0.35.0/Cargo.toml +45 -0
  113. package/native/vendor/markup5ever-0.35.0/LICENSE-APACHE +201 -0
  114. package/native/vendor/markup5ever-0.35.0/LICENSE-MIT +25 -0
  115. package/native/vendor/markup5ever-0.35.0/interface/mod.rs +422 -0
  116. package/native/vendor/markup5ever-0.35.0/interface/tree_builder.rs +280 -0
  117. package/native/vendor/markup5ever-0.35.0/lib.rs +59 -0
  118. package/native/vendor/markup5ever-0.35.0/serialize.rs +77 -0
  119. package/native/vendor/markup5ever-0.35.0/util/buffer_queue.rs +333 -0
  120. package/native/vendor/markup5ever-0.35.0/util/smallcharset.rs +88 -0
  121. package/package.json +137 -4
  122. package/rusteerio.darwin-arm64.node +0 -0
  123. package/rusteerio.darwin-x64.node +0 -0
  124. package/rusteerio.linux-arm64-gnu.node +0 -0
  125. package/rusteerio.linux-arm64-musl.node +0 -0
  126. package/rusteerio.linux-x64-gnu.node +0 -0
  127. package/rusteerio.linux-x64-musl.node +0 -0
  128. package/rusteerio.win32-arm64-msvc.node +0 -0
  129. package/rusteerio.win32-x64-msvc.node +0 -0
  130. package/scripts/check-native.mjs +15 -0
  131. package/scripts/check-release.mjs +235 -0
  132. package/scripts/fix-declarations.mjs +27 -0
  133. package/scripts/generate-notices.mjs +176 -0
  134. package/scripts/notices/README.md +13 -0
  135. package/scripts/notices/cheerio-MIT.txt +21 -0
  136. package/scripts/notices/html5ever-AUTHORS.txt +20 -0
  137. package/scripts/notices/html5ever-COPYRIGHT.txt +8 -0
  138. package/scripts/notices/html5ever-LICENSE-APACHE.txt +201 -0
  139. package/scripts/notices/html5ever-LICENSE-MIT.txt +25 -0
  140. package/scripts/notices/napi-rs-MIT.txt +43 -0
  141. package/scripts/notices/neon-MIT.txt +19 -0
  142. package/scripts/notices/runtime-01c266bced4a434da005.txt +3 -0
  143. package/scripts/notices/runtime-0a54e647fe54104658b5.txt +14 -0
  144. package/scripts/notices/runtime-0b74dfa0bcee5c420c6b.txt +25 -0
  145. package/scripts/notices/runtime-0d542e0c8804e39aa7f3.txt +177 -0
  146. package/scripts/notices/runtime-0f96a83840e146e43c0e.txt +21 -0
  147. package/scripts/notices/runtime-123a331b5dbf04c30097.txt +25 -0
  148. package/scripts/notices/runtime-172020dbfd5b53a226df.txt +34 -0
  149. package/scripts/notices/runtime-209fbbe0ad52d9235e37.txt +26 -0
  150. package/scripts/notices/runtime-23f18e03dc49df91622f.txt +23 -0
  151. package/scripts/notices/runtime-268872b9816f90fd8e85.txt +220 -0
  152. package/scripts/notices/runtime-35242e7a83f69875e6ed.txt +176 -0
  153. package/scripts/notices/runtime-378f5840b258e2779c39.txt +25 -0
  154. package/scripts/notices/runtime-4108245a1f2df9d4e94d.txt +25 -0
  155. package/scripts/notices/runtime-4455bf75a91154108304.txt +21 -0
  156. package/scripts/notices/runtime-553fffcd9b1cb158bc3e.txt +13 -0
  157. package/scripts/notices/runtime-62c7a1e35f56406896d7.txt +176 -0
  158. package/scripts/notices/runtime-6485b8ed310d3f0340bf.txt +25 -0
  159. package/scripts/notices/runtime-69fef7b0f322a6555415.txt +201 -0
  160. package/scripts/notices/runtime-6df43f6f4b5d4587f3d8.txt +187 -0
  161. package/scripts/notices/runtime-799e9ca9d179295ef372.txt +24 -0
  162. package/scripts/notices/runtime-7b63ecd5f1902af1b637.txt +25 -0
  163. package/scripts/notices/runtime-7bc7d5de2a0b793d4e1a.txt +21 -0
  164. package/scripts/notices/runtime-7e12e5df4bae12cb2158.txt +24 -0
  165. package/scripts/notices/runtime-861399f8c21c042b1105.txt +12 -0
  166. package/scripts/notices/runtime-8ada45cd9f843acf64e4.txt +201 -0
  167. package/scripts/notices/runtime-90eb64f0279b0d9432ac.txt +12 -0
  168. package/scripts/notices/runtime-a60eea817514531668d7.txt +201 -0
  169. package/scripts/notices/runtime-a7c936ff1ed8fa340172.txt +25 -0
  170. package/scripts/notices/runtime-ab6eec6caf0fa5775e41.txt +275 -0
  171. package/scripts/notices/runtime-b1181a40b2a7b25cf66f.txt +19 -0
  172. package/scripts/notices/runtime-b71bd43a069ca0641a9e.txt +25 -0
  173. package/scripts/notices/runtime-c16f8dcf1a368b83be78.txt +201 -0
  174. package/scripts/notices/runtime-c2cfccb812fe482101a8.txt +21 -0
  175. package/scripts/notices/runtime-e99d88d232bf57d70f0f.txt +25 -0
  176. package/scripts/notices/runtime-f32fb3b417a194167cfa.txt +9 -0
  177. package/scripts/notices/runtime-f5062c9a188d81dfe66b.txt +39 -0
  178. package/scripts/notices/runtime-f9070a832833fa7488fd.txt +4 -0
  179. package/scripts/notices/runtime-fab3dd6bdab226f1c086.txt +373 -0
  180. package/scripts/notices/runtime-fba3318d0c600380177e.txt +62 -0
  181. package/scripts/notices/runtime-ff8f68cb076caf8cefe7.txt +25 -0
  182. package/scripts/notices/runtime-ff92bed461f50338dd70.txt +74 -0
  183. package/scripts/notices/runtime.json +1632 -0
  184. package/scripts/notices/sources.json +555 -0
  185. package/scripts/notices/xray-MIT.txt +21 -0
  186. package/src/attributes.ts +271 -0
  187. package/src/codec.ts +74 -0
  188. package/src/dom.ts +87 -0
  189. package/src/extract-plan.ts +97 -0
  190. package/src/extract.ts +130 -0
  191. package/src/hooks.ts +220 -0
  192. package/src/index.ts +223 -0
  193. package/src/io.ts +491 -0
  194. package/src/native.ts +135 -0
  195. package/src/nodes.ts +290 -0
  196. package/src/parse.ts +53 -0
  197. package/src/parser-types.ts +157 -0
  198. package/src/router.ts +327 -0
  199. package/src/selection.ts +566 -0
  200. package/src/slim.ts +12 -0
  201. package/src/transport.ts +104 -0
  202. package/src/types.ts +186 -0
  203. package/src/utils.ts +29 -0
  204. package/src/workers.ts +21 -0
  205. package/tsconfig.json +15 -0
  206. package/tsup.config.ts +16 -0
package/src/nodes.ts ADDED
@@ -0,0 +1,290 @@
1
+ import type { NativeDocument, NativeNodeRecord } from './native.js';
2
+ import type { AnyNode } from './types.js';
3
+ import { nodePrototype } from './dom.js';
4
+ import { sameNodeSpace } from './router.js';
5
+
6
+ export interface NodeBinding { document: NativeDocument; id: number }
7
+ interface ViewState { document: NativeDocument; id: number; lease?: object; children?: AnyNode[]; attributes?: Record<string, string>; maps?: Record<string, Record<string, string>> }
8
+ interface NodeState { views: WeakMap<object, ViewState>; bindings: WeakMap<object, NodeBinding>; caches: WeakMap<object, Map<number, WeakRef<AnyNode>>>; finalizer: FinalizationRegistry<{ cache: Map<number, WeakRef<AnyNode>>; id: number }> }
9
+ const nodeStateKey = Symbol.for('rusteerio.native-node-views.v2');
10
+ const nodeGlobals = globalThis as typeof globalThis & { [key: symbol]: NodeState | undefined };
11
+ const nodeState: NodeState = nodeGlobals[nodeStateKey] ??= { views: new WeakMap(), bindings: new WeakMap(), caches: new WeakMap(), finalizer: new FinalizationRegistry(({ cache, id }) => { if (!cache.get(id)?.deref()) cache.delete(id); }) };
12
+ const { bindings, caches } = nodeState;
13
+ const arrayIndex = /^(?:0|[1-9]\d*)$/;
14
+
15
+ export function operation<T = any>(document: NativeDocument, command: string, args: unknown = {}): T {
16
+ const direct = (document as NativeDocument & { operate?(command: string, args: unknown): T }).operate;
17
+ if (direct) return direct.call(document, command, args);
18
+ const value = document.op(command, JSON.stringify(args));
19
+ return (value === undefined || value === '' ? undefined : JSON.parse(value)) as T;
20
+ }
21
+
22
+ export function nodeBinding(node: unknown): NodeBinding | undefined {
23
+ return node && typeof node === 'object' ? bindings.get(node) : undefined;
24
+ }
25
+
26
+ export function nodeId(node: unknown, document?: NativeDocument): number | undefined {
27
+ const binding = nodeBinding(node);
28
+ return binding && (!document || sameNodeSpace(document, binding.document)) ? binding.id : undefined;
29
+ }
30
+
31
+ /** Recreate parse5's null-prototype attribute maps and shared start-tag map. */
32
+ export function hydrateLocation<T>(location: T): T {
33
+ if (!location || typeof location !== 'object') return location;
34
+ const value = location as Record<string, any>;
35
+ if (value.attrs && typeof value.attrs === 'object') Object.setPrototypeOf(value.attrs, null);
36
+ if (value.startTag?.attrs && typeof value.startTag.attrs === 'object') {
37
+ Object.setPrototypeOf(value.startTag.attrs, null);
38
+ if (value.attrs && JSON.stringify(value.attrs) === JSON.stringify(value.startTag.attrs)) value.startTag.attrs = value.attrs;
39
+ }
40
+ return location;
41
+ }
42
+
43
+ export function nodeRecord(document: NativeDocument, id: number): NativeNodeRecord {
44
+ return operation(document, 'node', { id });
45
+ }
46
+
47
+ function setField(document: NativeDocument, id: number, field: string, value: unknown): void {
48
+ operation(document, 'setNode', { id, field, value });
49
+ }
50
+
51
+ function attributes(document: NativeDocument, id: number, field = 'attribs', prototype: object | null = (document as NativeDocument & { options?: { _useHtmlParser2?: boolean } }).options?._useHtmlParser2 === false ? null : Object.prototype): Record<string, string> {
52
+ const read = () => (nodeRecord(document, id) as any)?.[field] ?? {};
53
+ const target = Object.create(prototype);
54
+ return new Proxy(target, {
55
+ get(_target, key) { return typeof key === 'symbol' ? Reflect.get(target, key) : Object.hasOwn(read(), key) ? read()[key] : Reflect.get(target, key); },
56
+ set(_target, key, value) { setField(document, id, field, { ...read(), [key]: String(value) }); return true; },
57
+ deleteProperty(_target, key) { const values = { ...read() }; delete values[key]; setField(document, id, field, values); return true; },
58
+ ownKeys() { return Reflect.ownKeys(read()); },
59
+ has(_target, key) { return Object.hasOwn(read(), key) || key in target; },
60
+ getOwnPropertyDescriptor(_target, key) { return Object.hasOwn(read(), key) ? { value: read()[key], writable: true, enumerable: true, configurable: true } : undefined; },
61
+ defineProperty(_target, key, descriptor) { const values = { ...read(), [key]: String(descriptor.value) }; setField(document, id, field, values); return true; },
62
+ });
63
+ }
64
+
65
+ function children(document: NativeDocument, id: number): AnyNode[] {
66
+ const read = (): number[] => nodeRecord(document, id)?.children ?? [];
67
+ const snapshot = () => read().map((child) => getNode(document, child));
68
+ const save = (nodes: unknown[]) => setField(document, id, 'children', importNodes(document, nodes));
69
+ const mutating = new Set(['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse', 'copyWithin', 'fill']);
70
+ const target: AnyNode[] = [];
71
+ return new Proxy(target, {
72
+ get(_target, key, receiver) {
73
+ if (key === 'length') return read().length;
74
+ if (typeof key === 'string' && arrayIndex.test(key)) { const child = read()[Number(key)]; return child === undefined ? undefined : getNode(document, child); }
75
+ if (typeof key === 'string' && mutating.has(key)) return (...args: unknown[]) => {
76
+ const values = snapshot();
77
+ const result = Reflect.apply((Array.prototype as any)[key], values, args);
78
+ save(values);
79
+ return result === values ? receiver : result;
80
+ };
81
+ return Reflect.get(target, key, receiver);
82
+ },
83
+ set(_target, key, value) {
84
+ const values = snapshot();
85
+ if (key === 'length') values.length = value;
86
+ else if (typeof key === 'string' && arrayIndex.test(key)) values[Number(key)] = value;
87
+ else return Reflect.set(target, key, value);
88
+ save(values); return true;
89
+ },
90
+ deleteProperty(_target, key) { if (typeof key === 'string' && arrayIndex.test(key)) { const values = snapshot(); values.splice(Number(key), 1); save(values); return true; } return Reflect.deleteProperty(target, key); },
91
+ has(_target, key) { return typeof key === 'string' && arrayIndex.test(key) ? Number(key) < read().length : Reflect.has(target, key); },
92
+ ownKeys() { return [...read().map((_child, i) => String(i)), 'length']; },
93
+ getOwnPropertyDescriptor(_target, key) {
94
+ if (key === 'length') return { ...Reflect.getOwnPropertyDescriptor(target, 'length')!, value: read().length };
95
+ if (typeof key === 'string' && arrayIndex.test(key) && Number(key) < read().length) return { value: getNode(document, read()[Number(key)]), writable: true, enumerable: true, configurable: true };
96
+ return Reflect.getOwnPropertyDescriptor(target, key);
97
+ },
98
+ });
99
+ }
100
+
101
+ const parentAliases: Record<string, string> = { parentNode: 'parent', previousSibling: 'prev', nextSibling: 'next' };
102
+ const sourceFields = new Set(['type', 'name', 'data', 'namespace', 'prefix', 'startIndex', 'endIndex', 'sourceCodeLocation', 'x-name', 'x-publicId', 'x-systemId', 'x-mode']);
103
+ const tagTypes = new Set(['tag', 'script', 'style']);
104
+ const parentTypes = new Set(['root', 'tag', 'script', 'style', 'cdata']);
105
+ const dataTypes = new Set(['text', 'comment', 'directive']);
106
+ function viewKeys(record: NativeNodeRecord): string[] {
107
+ const keys = ['parent', 'prev', 'next', 'startIndex', 'endIndex'];
108
+ if (parentTypes.has(record.type)) keys.push('children');
109
+ if (record.data !== undefined) keys.push('data');
110
+ if (record.name !== undefined) keys.push('name');
111
+ if (tagTypes.has(record.type)) keys.push('attribs');
112
+ keys.push('type');
113
+ for (const field of sourceFields) if (!keys.includes(field) && field in record) keys.push(field);
114
+ if (tagTypes.has(record.type)) {
115
+ if ('attribsNamespace' in record) keys.push('x-attribsNamespace');
116
+ if ('attribsPrefix' in record) keys.push('x-attribsPrefix');
117
+ }
118
+ return keys;
119
+ }
120
+ function viewValue(state: ViewState, key: string, receiver: any): any {
121
+ const { document, id } = state;
122
+ const record = nodeRecord(document, id);
123
+ if (key === 'cloneNode') return cloneNode;
124
+ if (key === 'nodeType') return ({ root: 9, text: 3, comment: 8, cdata: 4 } as Record<string, number>)[record.type] ?? 1;
125
+ if (key === 'tagName' && tagTypes.has(record.type)) return record.name;
126
+ if (key === 'nodeValue' && dataTypes.has(record.type)) return record.data;
127
+ const pointer = parentAliases[key] ?? key;
128
+ if (['parent', 'prev', 'next'].includes(pointer)) return record[pointer] == null ? null : getNode(document, record[pointer]);
129
+ if (['children', 'childNodes', 'firstChild', 'lastChild'].includes(key) && parentTypes.has(record.type)) {
130
+ const list = state.children ??= children(document, id);
131
+ return key === 'firstChild' ? list[0] ?? null : key === 'lastChild' ? list[list.length - 1] ?? null : list;
132
+ }
133
+ if (key === 'attribs' && tagTypes.has(record.type)) return state.attributes ??= attributes(document, id);
134
+ if ((key === 'x-attribsNamespace' && 'attribsNamespace' in record || key === 'x-attribsPrefix' && 'attribsPrefix' in record) && tagTypes.has(record.type)) {
135
+ state.maps ??= {};
136
+ return state.maps[key] ??= attributes(document, id, key === 'x-attribsNamespace' ? 'attribsNamespace' : 'attribsPrefix');
137
+ }
138
+ if (key === 'attributes' && tagTypes.has(record.type)) {
139
+ const attrs = state.attributes ??= attributes(document, id);
140
+ return Object.keys(attrs).map((name) => ({ name, value: attrs[name], namespace: record.attribsNamespace?.[name], prefix: record.attribsPrefix?.[name] }));
141
+ }
142
+ if (key === 'sourceCodeLocation') return hydrateLocation(record[key]);
143
+ if (sourceFields.has(key)) return record[key] ?? (key === 'startIndex' || key === 'endIndex' ? null : undefined);
144
+ return undefined;
145
+ }
146
+ function writeView(state: ViewState, key: string, value: any): boolean {
147
+ const { document, id } = state;
148
+ const record = nodeRecord(document, id);
149
+ if (key === 'tagName' && tagTypes.has(record.type)) key = 'name';
150
+ else if (key === 'nodeValue' && dataTypes.has(record.type)) key = 'data';
151
+ else if (key === 'childNodes') key = 'children';
152
+ else key = parentAliases[key] ?? key;
153
+ if (sourceFields.has(key) || ['attribs', 'x-attribsNamespace', 'x-attribsPrefix'].includes(key)) { setField(document, id, key, value); return true; }
154
+ if (key === 'children' && parentTypes.has(record.type)) { setField(document, id, key, importNodes(document, value)); return true; }
155
+ if (['parent', 'prev', 'next'].includes(key)) { setField(document, id, key, value == null ? null : importNodes(document, [value])[0]); return true; }
156
+ return false;
157
+ }
158
+ const nodeHandler: ProxyHandler<object> = {
159
+ get(target, key, receiver) {
160
+ if (Reflect.getOwnPropertyDescriptor(target, key)) return Reflect.get(target, key, receiver);
161
+ if (typeof key === 'string') {
162
+ const state = nodeState.views.get(target)!;
163
+ if (key === 'cloneNode' || key === 'nodeType' || sourceFields.has(key) || ['tagName', 'nodeValue', 'parent', 'prev', 'next', 'parentNode', 'previousSibling', 'nextSibling', 'children', 'childNodes', 'firstChild', 'lastChild', 'attribs', 'attributes', 'x-attribsNamespace', 'x-attribsPrefix'].includes(key)) return viewValue(state, key, receiver);
164
+ }
165
+ return Reflect.get(target, key, receiver);
166
+ },
167
+ set(target, key, value, receiver) {
168
+ if (Reflect.getOwnPropertyDescriptor(target, key)) return Reflect.set(target, key, value, receiver);
169
+ if (typeof key === 'string' && writeView(nodeState.views.get(target)!, key, value)) return true;
170
+ return Reflect.set(target, key, value, receiver);
171
+ },
172
+ has(target, key) { return Reflect.has(target, key) || typeof key === 'string' && (viewKeys(nodeRecord(nodeState.views.get(target)!.document, nodeState.views.get(target)!.id)).includes(key) || ['cloneNode', 'nodeType', 'parentNode', 'previousSibling', 'nextSibling'].includes(key)); },
173
+ ownKeys(target) { const state = nodeState.views.get(target)!; return [...new Set([...viewKeys(nodeRecord(state.document, state.id)), ...Reflect.ownKeys(target)])]; },
174
+ getOwnPropertyDescriptor(target, key) {
175
+ const existing = Reflect.getOwnPropertyDescriptor(target, key);
176
+ if (existing) return existing;
177
+ const state = nodeState.views.get(target)!;
178
+ if (typeof key === 'string' && viewKeys(nodeRecord(state.document, state.id)).includes(key)) return { value: viewValue(state, key, undefined), configurable: true, enumerable: true, writable: true };
179
+ return undefined;
180
+ },
181
+ };
182
+
183
+ /** Stable DOM node identities; each property reads or updates the Rust arena. */
184
+ export function getNode(document: NativeDocument, id: number, original?: any): AnyNode {
185
+ const cacheKey = document.nodeSpace ?? document;
186
+ let cache = caches.get(cacheKey);
187
+ if (!cache) caches.set(cacheKey, cache = new Map());
188
+ const existing = cache.get(id)?.deref();
189
+ if (existing) return existing;
190
+ document = (document as NativeDocument & { nodeDocument?(id: number): NativeDocument }).nodeDocument?.(id) ?? document;
191
+ const lease = (document as NativeDocument & { retainNodes?(ids: number[]): object }).retainNodes?.([id]);
192
+ const record = nodeRecord(document, id);
193
+ if (!record) return undefined as unknown as AnyNode;
194
+ if (original === undefined) {
195
+ const target = Object.create(nodePrototype(record.type));
196
+ const node = new Proxy(target, nodeHandler) as AnyNode;
197
+ nodeState.views.set(target, { document, id, lease });
198
+ cache.set(id, new WeakRef(node));
199
+ nodeState.finalizer.register(node, { cache, id });
200
+ bindings.set(node, { document, id });
201
+ return node;
202
+ }
203
+ const node: any = original;
204
+ cache.set(id, new WeakRef(node));
205
+ nodeState.finalizer.register(node, { cache, id });
206
+ bindings.set(node, { document, id });
207
+ const read = (): any => { void lease; return nodeRecord(document, id); };
208
+ const define = (key: string, get: () => unknown, set?: (value: any) => void, enumerable = true) => {
209
+ try { Object.defineProperty(node, key, { configurable: true, enumerable, get, ...(set ? { set } : {}) }); } catch { /* Foreign user properties may be non-configurable. */ }
210
+ };
211
+ for (const field of ['type', 'name', 'data', 'namespace', 'prefix', 'startIndex', 'endIndex', 'sourceCodeLocation', 'x-name', 'x-publicId', 'x-systemId', 'x-mode']) {
212
+ if (field in record || ['type', 'startIndex', 'endIndex'].includes(field)) define(field, () => (field === 'sourceCodeLocation' ? hydrateLocation(read()[field]) : read()[field]) ?? (field === 'startIndex' || field === 'endIndex' ? null : undefined), (value) => setField(document, id, field, value));
213
+ }
214
+ for (const field of ['parent', 'prev', 'next']) define(field, () => { const value = read()[field]; return value === null || value === undefined ? null : getNode(document, value); }, (value) => setField(document, id, field, value == null ? null : importNodes(document, [value])[0]));
215
+ for (const [alias, field] of [['parentNode', 'parent'], ['previousSibling', 'prev'], ['nextSibling', 'next']]) define(alias, () => node[field], (value) => { node[field] = value; }, false);
216
+ if ('children' in record && ['root', 'tag', 'script', 'style', 'cdata'].includes(record.type)) {
217
+ const list = children(document, id);
218
+ define('children', () => list, (value) => setField(document, id, 'children', importNodes(document, value)));
219
+ define('childNodes', () => list, (value) => { node.children = value; }, false);
220
+ define('firstChild', () => list[0] ?? null, undefined, false);
221
+ define('lastChild', () => list[list.length - 1] ?? null, undefined, false);
222
+ }
223
+ if (['tag', 'script', 'style'].includes(record.type)) {
224
+ const attrs = attributes(document, id, 'attribs', Object.getPrototypeOf(original.attribs ?? {}));
225
+ define('attribs', () => attrs, (value) => setField(document, id, 'attribs', value));
226
+ define('tagName', () => node.name, (value) => { node.name = value; }, false);
227
+ for (const field of ['x-attribsNamespace', 'x-attribsPrefix']) {
228
+ if (!((field === 'x-attribsNamespace' ? 'attribsNamespace' : 'attribsPrefix') in record) && !Object.hasOwn(original, field)) continue;
229
+ const values = attributes(document, id, field === 'x-attribsNamespace' ? 'attribsNamespace' : 'attribsPrefix');
230
+ define(field, () => values, (value) => setField(document, id, field, value));
231
+ }
232
+ define('attributes', () => Object.keys(attrs).map((name) => ({ name, value: attrs[name], namespace: read().attribsNamespace?.[name], prefix: read().attribsPrefix?.[name] })), undefined, false);
233
+ }
234
+ if (['text', 'comment', 'directive'].includes(record.type)) define('nodeValue', () => node.data, (value) => { node.data = value; }, false);
235
+ define('nodeType', () => ({ root: 9, text: 3, comment: 8, cdata: 4 } as Record<string, number>)[read().type] ?? 1, undefined, false);
236
+ Object.defineProperty(node, 'cloneNode', { configurable: true, enumerable: false, writable: true, value: cloneNode });
237
+ return node;
238
+ }
239
+
240
+ /** Clone through the receiver's current native owner, including borrowed calls. */
241
+ export function cloneNode<T extends AnyNode>(this: T, recursive = false): T {
242
+ const binding = nodeBinding(this);
243
+ if (!binding) throw new TypeError('cloneNode requires a native DOM node receiver');
244
+ return getNode(binding.document, operation<number[]>(binding.document, 'clone', { ids: [binding.id], deep: recursive })[0]) as T;
245
+ }
246
+
247
+ /** Import external DOM nodes once and keep their object identities as handles. */
248
+ export function importNodes(document: NativeDocument, input: unknown): number[] {
249
+ if (input == null || input === false) return [];
250
+ const values: any[] = Array.isArray(input) || (typeof input === 'object' && 'length' in input && !('type' in input)) ? Array.from(input as ArrayLike<any>) : [input];
251
+ const result: number[] = [];
252
+ for (const node of values) {
253
+ if (node == null) continue;
254
+ const existing = nodeId(node, document);
255
+ if (existing !== undefined) { document.retainNode?.(existing); result.push(existing); continue; }
256
+ if (typeof node !== 'object' || typeof node.type !== 'string') continue;
257
+ const records: any[] = [];
258
+ const originals = new Map<number, any>();
259
+ const visit = (value: any, parent?: number): number => {
260
+ const id = records.length;
261
+ const record: any = { id, type: value.type, children: [], ...(parent === undefined ? {} : { parent }) };
262
+ records.push(record); originals.set(id, value);
263
+ for (const field of ['name', 'data', 'namespace', 'prefix', 'startIndex', 'endIndex', 'sourceCodeLocation', 'x-name', 'x-publicId', 'x-systemId', 'x-mode']) if (value[field] !== undefined) record[field] = value[field];
264
+ if (value.attribs) record.attribs = { ...value.attribs };
265
+ if (value['x-attribsNamespace']) record.attribsNamespace = { ...value['x-attribsNamespace'] };
266
+ if (value['x-attribsPrefix']) record.attribsPrefix = { ...value['x-attribsPrefix'] };
267
+ record.children = (value.children ?? []).map((child: any) => visit(child, id));
268
+ return id;
269
+ };
270
+ const root = visit(node);
271
+ const imported = operation<number[]>(document, 'import', { nodes: records, roots: [root] });
272
+ if (!imported.length) continue;
273
+ const adopt = (oldId: number, newId: number): void => {
274
+ const source = originals.get(oldId);
275
+ const oldChildren = records[oldId].children;
276
+ const newChildren = nodeRecord(document, newId).children ?? [];
277
+ // A node already belonging to another Rust document must retain its
278
+ // original document handle. Imported clones receive their own handles.
279
+ getNode(document, newId, nodeBinding(source) ? undefined : source);
280
+ for (let i = 0; i < oldChildren.length; i++) if (newChildren[i] !== undefined) adopt(oldChildren[i], newChildren[i]);
281
+ };
282
+ adopt(root, imported[0]);
283
+ result.push(imported[0]);
284
+ }
285
+ return result;
286
+ }
287
+
288
+ export const isTag = (node: any): boolean => !!node && ['tag', 'script', 'style'].includes(node.type);
289
+ export const isDocument = (node: any): boolean => node?.type === 'root';
290
+ export const hasChildren = (node: any): boolean => !!node && 'children' in node;
package/src/parse.ts ADDED
@@ -0,0 +1,53 @@
1
+ import { requireNative } from './native.js';
2
+ import { getNode, importNodes, nodeBinding, operation } from './nodes.js';
3
+ import { routeDocument } from './router.js';
4
+ import { parseNativeDocument, cleanParserOptions } from './hooks.js';
5
+ import type { AnyNode, Document, InternalOptions, ParentNode } from './types.js';
6
+
7
+ type ParseContent = string | Buffer | Document | AnyNode | AnyNode[];
8
+ type Parser = (content: string, options: InternalOptions, isDocument: boolean, context: ParentNode | null) => Document;
9
+
10
+ /** Parse with the Rust HTML5 or HTML/XML engine, preserving fragment context. */
11
+ function parseWithNative(content: string, options: InternalOptions, isDocument: boolean, context: ParentNode | null): Document {
12
+ if (!isDocument && context) {
13
+ const document = nodeBinding(context)?.document
14
+ ?? routeDocument(new (requireNative().NativeDocument)('', false, JSON.stringify(cleanParserOptions(options))), options);
15
+ const contextId = importNodes(document, [context])[0];
16
+ const children = operation<number[]>(document, 'create', { html: content, contextId, options });
17
+ const root = operation<number>(document, 'createNode', { type: 'root', options });
18
+ operation(document, 'setNode', { id: root, field: 'children', value: children, options });
19
+ return getNode(document, root) as Document;
20
+ }
21
+ const document = parseNativeDocument(content, options, isDocument);
22
+ return getNode(document, document.rootId()) as Document;
23
+ }
24
+
25
+ /** The HTML5 adapter uses Rust's HTML5 tree builder. */
26
+ export function parseWithParse5(content: string, options: InternalOptions, isDocument: boolean, context: ParentNode | null): Document {
27
+ return parseWithNative(content, { ...options, _useHtmlParser2: false, xml: false, xmlMode: false }, isDocument, context);
28
+ }
29
+
30
+ /** The htmlparser2-compatible adapter uses the Rust HTML/XML tokenizer. */
31
+ export function parseWithHtmlparser2(content: string, options: InternalOptions): Document {
32
+ return parseWithNative(content, { ...options, _useHtmlParser2: true }, false, null);
33
+ }
34
+
35
+ export { parseWithHtmlparser2 as parseDocument };
36
+
37
+ /** Normalize parser inputs while keeping every DOM operation in the native arena. */
38
+ export function getParse(parser: Parser) {
39
+ return function parse(content: ParseContent, options: InternalOptions, isDocument: boolean, context: ParentNode | null): Document {
40
+ if (Buffer.isBuffer(content)) content = content.toString();
41
+ if (typeof content === 'string') return parser(content, options, isDocument, context);
42
+ if (!Array.isArray(content) && content.type === 'root' && nodeBinding(content)) return content;
43
+ const document = routeDocument(new (requireNative().NativeDocument)('', false, JSON.stringify(cleanParserOptions(options))), options);
44
+ const ids = importNodes(document, content);
45
+ if (!Array.isArray(content) && content.type === 'root') return getNode(document, ids[0]) as Document;
46
+ operation(document, 'setNode', { id: document.rootId(), field: 'children', value: ids, options });
47
+ return getNode(document, document.rootId()) as Document;
48
+ };
49
+ }
50
+
51
+ export const parse = getParse((content, options, isDocument, context) => options._useHtmlParser2
52
+ ? parseWithHtmlparser2(content, options)
53
+ : parseWithParse5(content, options, isDocument, context));
@@ -0,0 +1,157 @@
1
+ import type { AnyNode, ParentNode, ChildNode, Document, Element, Comment, Text, ProcessingInstruction, SourceCodeLocation, TagSourceCodeLocation } from './types.js';
2
+
3
+ /** Parse5-compatible diagnostics, declared locally without a parser dependency. */
4
+ declare enum ERR {
5
+ controlCharacterInInputStream = "control-character-in-input-stream",
6
+ noncharacterInInputStream = "noncharacter-in-input-stream",
7
+ surrogateInInputStream = "surrogate-in-input-stream",
8
+ nonVoidHtmlElementStartTagWithTrailingSolidus = "non-void-html-element-start-tag-with-trailing-solidus",
9
+ endTagWithAttributes = "end-tag-with-attributes",
10
+ endTagWithTrailingSolidus = "end-tag-with-trailing-solidus",
11
+ unexpectedSolidusInTag = "unexpected-solidus-in-tag",
12
+ unexpectedNullCharacter = "unexpected-null-character",
13
+ unexpectedQuestionMarkInsteadOfTagName = "unexpected-question-mark-instead-of-tag-name",
14
+ invalidFirstCharacterOfTagName = "invalid-first-character-of-tag-name",
15
+ unexpectedEqualsSignBeforeAttributeName = "unexpected-equals-sign-before-attribute-name",
16
+ missingEndTagName = "missing-end-tag-name",
17
+ unexpectedCharacterInAttributeName = "unexpected-character-in-attribute-name",
18
+ unknownNamedCharacterReference = "unknown-named-character-reference",
19
+ missingSemicolonAfterCharacterReference = "missing-semicolon-after-character-reference",
20
+ unexpectedCharacterAfterDoctypeSystemIdentifier = "unexpected-character-after-doctype-system-identifier",
21
+ unexpectedCharacterInUnquotedAttributeValue = "unexpected-character-in-unquoted-attribute-value",
22
+ eofBeforeTagName = "eof-before-tag-name",
23
+ eofInTag = "eof-in-tag",
24
+ missingAttributeValue = "missing-attribute-value",
25
+ missingWhitespaceBetweenAttributes = "missing-whitespace-between-attributes",
26
+ missingWhitespaceAfterDoctypePublicKeyword = "missing-whitespace-after-doctype-public-keyword",
27
+ missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers = "missing-whitespace-between-doctype-public-and-system-identifiers",
28
+ missingWhitespaceAfterDoctypeSystemKeyword = "missing-whitespace-after-doctype-system-keyword",
29
+ missingQuoteBeforeDoctypePublicIdentifier = "missing-quote-before-doctype-public-identifier",
30
+ missingQuoteBeforeDoctypeSystemIdentifier = "missing-quote-before-doctype-system-identifier",
31
+ missingDoctypePublicIdentifier = "missing-doctype-public-identifier",
32
+ missingDoctypeSystemIdentifier = "missing-doctype-system-identifier",
33
+ abruptDoctypePublicIdentifier = "abrupt-doctype-public-identifier",
34
+ abruptDoctypeSystemIdentifier = "abrupt-doctype-system-identifier",
35
+ cdataInHtmlContent = "cdata-in-html-content",
36
+ incorrectlyOpenedComment = "incorrectly-opened-comment",
37
+ eofInScriptHtmlCommentLikeText = "eof-in-script-html-comment-like-text",
38
+ eofInDoctype = "eof-in-doctype",
39
+ nestedComment = "nested-comment",
40
+ abruptClosingOfEmptyComment = "abrupt-closing-of-empty-comment",
41
+ eofInComment = "eof-in-comment",
42
+ incorrectlyClosedComment = "incorrectly-closed-comment",
43
+ eofInCdata = "eof-in-cdata",
44
+ absenceOfDigitsInNumericCharacterReference = "absence-of-digits-in-numeric-character-reference",
45
+ nullCharacterReference = "null-character-reference",
46
+ surrogateCharacterReference = "surrogate-character-reference",
47
+ characterReferenceOutsideUnicodeRange = "character-reference-outside-unicode-range",
48
+ controlCharacterReference = "control-character-reference",
49
+ noncharacterCharacterReference = "noncharacter-character-reference",
50
+ missingWhitespaceBeforeDoctypeName = "missing-whitespace-before-doctype-name",
51
+ missingDoctypeName = "missing-doctype-name",
52
+ invalidCharacterSequenceAfterDoctypeName = "invalid-character-sequence-after-doctype-name",
53
+ duplicateAttribute = "duplicate-attribute",
54
+ nonConformingDoctype = "non-conforming-doctype",
55
+ missingDoctype = "missing-doctype",
56
+ misplacedDoctype = "misplaced-doctype",
57
+ endTagWithoutMatchingOpenElement = "end-tag-without-matching-open-element",
58
+ closingOfElementWithOpenChildElements = "closing-of-element-with-open-child-elements",
59
+ disallowedContentInNoscriptInHead = "disallowed-content-in-noscript-in-head",
60
+ openElementsLeftAfterEof = "open-elements-left-after-eof",
61
+ abandonedHeadElementChild = "abandoned-head-element-child",
62
+ misplacedStartTagForHeadElement = "misplaced-start-tag-for-head-element",
63
+ nestedNoscriptInHead = "nested-noscript-in-head",
64
+ eofInElementThatCanContainOnlyText = "eof-in-element-that-can-contain-only-text"
65
+ }
66
+
67
+ export type ParserErrorCode = ERR;
68
+ export interface ParserError extends SourceCodeLocation { code: ParserErrorCode }
69
+ export type ParserErrorHandler = (error: ParserError) => void;
70
+
71
+ declare enum NS {
72
+ HTML = 'http://www.w3.org/1999/xhtml',
73
+ MATHML = 'http://www.w3.org/1998/Math/MathML',
74
+ SVG = 'http://www.w3.org/2000/svg',
75
+ XLINK = 'http://www.w3.org/1999/xlink',
76
+ XML = 'http://www.w3.org/XML/1998/namespace',
77
+ XMLNS = 'http://www.w3.org/2000/xmlns/',
78
+ }
79
+ declare enum DOCUMENT_MODE {
80
+ NO_QUIRKS = 'no-quirks', QUIRKS = 'quirks', LIMITED_QUIRKS = 'limited-quirks',
81
+ }
82
+ export type NamespaceURI = NS;
83
+ export type DocumentMode = DOCUMENT_MODE;
84
+ export interface TreeAdapterAttribute { name: string; value: string; namespace?: string; prefix?: string }
85
+
86
+ /** The HTML5 adapter shape used by Cheerio's DOM representation. */
87
+ export interface TreeAdapter {
88
+ adoptAttributes(recipient: Element, attrs: TreeAdapterAttribute[]): void;
89
+ appendChild(parentNode: ParentNode, newNode: ChildNode): void;
90
+ createCommentNode(data: string): Comment;
91
+ createTextNode(value: string): Text;
92
+ createDocument(): Document;
93
+ createDocumentFragment(): Document;
94
+ createElement(tagName: string, namespaceURI: NamespaceURI, attrs: TreeAdapterAttribute[]): Element;
95
+ detachNode(node: ChildNode): void;
96
+ getAttrList(element: Element): TreeAdapterAttribute[];
97
+ getChildNodes(node: ParentNode): ChildNode[];
98
+ getCommentNodeContent(node: Comment): string;
99
+ getDocumentMode(document: Document): DocumentMode;
100
+ getDocumentTypeNodeName(node: ProcessingInstruction): string;
101
+ getDocumentTypeNodePublicId(node: ProcessingInstruction): string;
102
+ getDocumentTypeNodeSystemId(node: ProcessingInstruction): string;
103
+ getFirstChild(node: ParentNode): ChildNode | null;
104
+ getNamespaceURI(element: Element): NamespaceURI;
105
+ getNodeSourceCodeLocation(node: AnyNode): TagSourceCodeLocation | undefined | null;
106
+ getParentNode(node: AnyNode): ParentNode | null;
107
+ getTagName(element: Element): string;
108
+ getTextNodeContent(node: Text): string;
109
+ getTemplateContent(element: Element): Document;
110
+ insertBefore(parent: ParentNode, child: ChildNode, reference: ChildNode): void;
111
+ insertText(parent: ParentNode, text: string): void;
112
+ insertTextBefore(parent: ParentNode, text: string, reference: ChildNode): void;
113
+ isCommentNode(node: AnyNode): node is Comment;
114
+ isDocumentTypeNode(node: AnyNode): node is ProcessingInstruction;
115
+ isElementNode(node: AnyNode): node is Element;
116
+ isTextNode(node: AnyNode): node is Text;
117
+ setDocumentMode(document: Document, mode: DocumentMode): void;
118
+ setDocumentType(document: Document, name: string, publicId: string, systemId: string): void;
119
+ setNodeSourceCodeLocation(node: AnyNode, location: TagSourceCodeLocation | null): void;
120
+ updateNodeSourceCodeLocation(node: AnyNode, location: Partial<TagSourceCodeLocation>): void;
121
+ setTemplateContent(element: Element, content: Document): void;
122
+ onItemPush?: (item: Element) => void;
123
+ onItemPop?: (item: Element, newTop: ParentNode) => void;
124
+ }
125
+
126
+ declare enum QuoteType { NoValue = 0, Unquoted = 1, Single = 2, Double = 3 }
127
+ export interface TokenizerCallbacks {
128
+ onattribdata(start: number, endIndex: number): void;
129
+ onattribentity(codepoint: number): void;
130
+ onattribend(quote: QuoteType, endIndex: number): void;
131
+ onattribname(start: number, endIndex: number): void;
132
+ oncdata(start: number, endIndex: number, endOffset: number): void;
133
+ onclosetag(start: number, endIndex: number): void;
134
+ oncomment(start: number, endIndex: number, endOffset: number): void;
135
+ ondeclaration(start: number, endIndex: number): void;
136
+ onend(): void;
137
+ onopentagend(endIndex: number): void;
138
+ onopentagname(start: number, endIndex: number): void;
139
+ onprocessinginstruction(start: number, endIndex: number): void;
140
+ onselfclosingtag(endIndex: number): void;
141
+ ontext(start: number, endIndex: number): void;
142
+ ontextentity(codepoint: number, endIndex: number): void;
143
+ }
144
+ export interface Tokenizer {
145
+ running: boolean;
146
+ reset(): void;
147
+ write(chunk: string): void;
148
+ end(): void;
149
+ pause(): void;
150
+ resume(): void;
151
+ }
152
+ export interface TokenizerOptions { xmlMode?: boolean; decodeEntities?: boolean }
153
+ export interface TokenizerConstructor {
154
+ new (options: TokenizerOptions, callbacks: TokenizerCallbacks): Tokenizer;
155
+ // The native facade accepts third-party tokenizer classes with private state.
156
+ new (options: TokenizerOptions, callbacks: TokenizerCallbacks): any;
157
+ }