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.
- package/CONTRIBUTING.md +73 -0
- package/Cargo.lock +1051 -0
- package/Cargo.toml +36 -0
- package/LICENSE +21 -0
- package/README.md +252 -2
- package/RELEASING.md +138 -0
- package/THIRD_PARTY_NOTICES.md +7443 -0
- package/build.rs +3 -0
- package/dist/chunk-DKULX6VO.mjs +3185 -0
- package/dist/chunk-DKULX6VO.mjs.map +1 -0
- package/dist/chunk-OHPGEY3E.mjs +32 -0
- package/dist/chunk-OHPGEY3E.mjs.map +1 -0
- package/dist/index.cjs +3230 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +113 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.mjs +38 -0
- package/dist/index.mjs.map +1 -0
- package/dist/slim.cjs +2441 -0
- package/dist/slim.cjs.map +1 -0
- package/dist/slim.d.mts +11 -0
- package/dist/slim.d.ts +11 -0
- package/dist/slim.mjs +19 -0
- package/dist/slim.mjs.map +1 -0
- package/dist/types-BP6TpxE5.d.mts +532 -0
- package/dist/types-BP6TpxE5.d.ts +532 -0
- package/dist/utils.cjs +61 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.mts +13 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.mjs +17 -0
- package/dist/utils.mjs.map +1 -0
- package/native/src/arena.rs +1781 -0
- package/native/src/attributes.rs +923 -0
- package/native/src/codec.rs +172 -0
- package/native/src/diagnostics.rs +1249 -0
- package/native/src/extraction.rs +226 -0
- package/native/src/gc.rs +166 -0
- package/native/src/hook_sink.rs +727 -0
- package/native/src/hook_stream.rs +513 -0
- package/native/src/lib.rs +2095 -0
- package/native/src/location.rs +392 -0
- package/native/src/runtime.rs +189 -0
- package/native/src/selector.rs +1287 -0
- package/native/src/sink.rs +261 -0
- package/native/src/stream.rs +334 -0
- package/native/src/tokenizer.rs +355 -0
- package/native/src/tracker.rs +232 -0
- package/native/vendor/README.md +25 -0
- package/native/vendor/html5ever-0.35.0/.cargo_vcs_info.json +6 -0
- package/native/vendor/html5ever-0.35.0/Cargo.lock +828 -0
- package/native/vendor/html5ever-0.35.0/Cargo.toml +85 -0
- package/native/vendor/html5ever-0.35.0/LICENSE-APACHE +201 -0
- package/native/vendor/html5ever-0.35.0/LICENSE-MIT +25 -0
- package/native/vendor/html5ever-0.35.0/README.md +60 -0
- package/native/vendor/html5ever-0.35.0/benches/html5ever.rs +86 -0
- package/native/vendor/html5ever-0.35.0/data/bench/lipsum-zh.html +19 -0
- package/native/vendor/html5ever-0.35.0/data/bench/lipsum.html +40 -0
- package/native/vendor/html5ever-0.35.0/data/bench/medium-fragment.html +24 -0
- package/native/vendor/html5ever-0.35.0/data/bench/small-fragment.html +7 -0
- package/native/vendor/html5ever-0.35.0/data/bench/strong.html +1 -0
- package/native/vendor/html5ever-0.35.0/data/bench/tiny-fragment.html +1 -0
- package/native/vendor/html5ever-0.35.0/examples/arena.rs +356 -0
- package/native/vendor/html5ever-0.35.0/examples/capi/tokenize.c +74 -0
- package/native/vendor/html5ever-0.35.0/examples/noop-tokenize.rs +47 -0
- package/native/vendor/html5ever-0.35.0/examples/noop-tree-builder.rs +132 -0
- package/native/vendor/html5ever-0.35.0/examples/print-tree-actions.rs +185 -0
- package/native/vendor/html5ever-0.35.0/examples/tokenize.rs +111 -0
- package/native/vendor/html5ever-0.35.0/src/driver.rs +148 -0
- package/native/vendor/html5ever-0.35.0/src/lib.rs +30 -0
- package/native/vendor/html5ever-0.35.0/src/macros.rs +34 -0
- package/native/vendor/html5ever-0.35.0/src/serialize/mod.rs +255 -0
- package/native/vendor/html5ever-0.35.0/src/tokenizer/char_ref/mod.rs +451 -0
- package/native/vendor/html5ever-0.35.0/src/tokenizer/interface.rs +99 -0
- package/native/vendor/html5ever-0.35.0/src/tokenizer/mod.rs +2305 -0
- package/native/vendor/html5ever-0.35.0/src/tokenizer/states.rs +97 -0
- package/native/vendor/html5ever-0.35.0/src/tree_builder/data.rs +170 -0
- package/native/vendor/html5ever-0.35.0/src/tree_builder/mod.rs +1848 -0
- package/native/vendor/html5ever-0.35.0/src/tree_builder/rules.rs +1494 -0
- package/native/vendor/html5ever-0.35.0/src/tree_builder/tag_sets.rs +114 -0
- package/native/vendor/html5ever-0.35.0/src/tree_builder/types.rs +91 -0
- package/native/vendor/html5ever-0.35.0/src/util/str.rs +52 -0
- package/native/vendor/html5gum-0.8.4/Cargo.lock +1006 -0
- package/native/vendor/html5gum-0.8.4/Cargo.toml +109 -0
- package/native/vendor/html5gum-0.8.4/LICENSE +19 -0
- package/native/vendor/html5gum-0.8.4/README.md +110 -0
- package/native/vendor/html5gum-0.8.4/benches/files/0050.html +2131 -0
- package/native/vendor/html5gum-0.8.4/benches/files/6D30.html +1004 -0
- package/native/vendor/html5gum-0.8.4/benches/files.rs +32 -0
- package/native/vendor/html5gum-0.8.4/benches/patterns.rs +31 -0
- package/native/vendor/html5gum-0.8.4/src/arrayvec.rs +29 -0
- package/native/vendor/html5gum-0.8.4/src/char_validator.rs +134 -0
- package/native/vendor/html5gum-0.8.4/src/emitters/callback.rs +676 -0
- package/native/vendor/html5gum-0.8.4/src/emitters/default.rs +207 -0
- package/native/vendor/html5gum-0.8.4/src/emitters/emitter.rs +344 -0
- package/native/vendor/html5gum-0.8.4/src/emitters/html5ever.rs +306 -0
- package/native/vendor/html5gum-0.8.4/src/emitters/mod.rs +25 -0
- package/native/vendor/html5gum-0.8.4/src/entities.rs +3342 -0
- package/native/vendor/html5gum-0.8.4/src/error.rs +96 -0
- package/native/vendor/html5gum-0.8.4/src/htmlstring.rs +130 -0
- package/native/vendor/html5gum-0.8.4/src/lib.rs +66 -0
- package/native/vendor/html5gum-0.8.4/src/machine.rs +2136 -0
- package/native/vendor/html5gum-0.8.4/src/machine_helper.rs +277 -0
- package/native/vendor/html5gum-0.8.4/src/read_helper.rs +244 -0
- package/native/vendor/html5gum-0.8.4/src/reader.rs +440 -0
- package/native/vendor/html5gum-0.8.4/src/span.rs +98 -0
- package/native/vendor/html5gum-0.8.4/src/state.rs +16 -0
- package/native/vendor/html5gum-0.8.4/src/testutils.rs +71 -0
- package/native/vendor/html5gum-0.8.4/src/tokenizer.rs +189 -0
- package/native/vendor/html5gum-0.8.4/src/utils.rs +88 -0
- package/native/vendor/markup5ever-0.35.0/.cargo_vcs_info.json +6 -0
- package/native/vendor/markup5ever-0.35.0/Cargo.toml +45 -0
- package/native/vendor/markup5ever-0.35.0/LICENSE-APACHE +201 -0
- package/native/vendor/markup5ever-0.35.0/LICENSE-MIT +25 -0
- package/native/vendor/markup5ever-0.35.0/interface/mod.rs +422 -0
- package/native/vendor/markup5ever-0.35.0/interface/tree_builder.rs +280 -0
- package/native/vendor/markup5ever-0.35.0/lib.rs +59 -0
- package/native/vendor/markup5ever-0.35.0/serialize.rs +77 -0
- package/native/vendor/markup5ever-0.35.0/util/buffer_queue.rs +333 -0
- package/native/vendor/markup5ever-0.35.0/util/smallcharset.rs +88 -0
- package/package.json +137 -4
- package/rusteerio.darwin-arm64.node +0 -0
- package/rusteerio.darwin-x64.node +0 -0
- package/rusteerio.linux-arm64-gnu.node +0 -0
- package/rusteerio.linux-arm64-musl.node +0 -0
- package/rusteerio.linux-x64-gnu.node +0 -0
- package/rusteerio.linux-x64-musl.node +0 -0
- package/rusteerio.win32-arm64-msvc.node +0 -0
- package/rusteerio.win32-x64-msvc.node +0 -0
- package/scripts/check-native.mjs +15 -0
- package/scripts/check-release.mjs +235 -0
- package/scripts/fix-declarations.mjs +27 -0
- package/scripts/generate-notices.mjs +176 -0
- package/scripts/notices/README.md +13 -0
- package/scripts/notices/cheerio-MIT.txt +21 -0
- package/scripts/notices/html5ever-AUTHORS.txt +20 -0
- package/scripts/notices/html5ever-COPYRIGHT.txt +8 -0
- package/scripts/notices/html5ever-LICENSE-APACHE.txt +201 -0
- package/scripts/notices/html5ever-LICENSE-MIT.txt +25 -0
- package/scripts/notices/napi-rs-MIT.txt +43 -0
- package/scripts/notices/neon-MIT.txt +19 -0
- package/scripts/notices/runtime-01c266bced4a434da005.txt +3 -0
- package/scripts/notices/runtime-0a54e647fe54104658b5.txt +14 -0
- package/scripts/notices/runtime-0b74dfa0bcee5c420c6b.txt +25 -0
- package/scripts/notices/runtime-0d542e0c8804e39aa7f3.txt +177 -0
- package/scripts/notices/runtime-0f96a83840e146e43c0e.txt +21 -0
- package/scripts/notices/runtime-123a331b5dbf04c30097.txt +25 -0
- package/scripts/notices/runtime-172020dbfd5b53a226df.txt +34 -0
- package/scripts/notices/runtime-209fbbe0ad52d9235e37.txt +26 -0
- package/scripts/notices/runtime-23f18e03dc49df91622f.txt +23 -0
- package/scripts/notices/runtime-268872b9816f90fd8e85.txt +220 -0
- package/scripts/notices/runtime-35242e7a83f69875e6ed.txt +176 -0
- package/scripts/notices/runtime-378f5840b258e2779c39.txt +25 -0
- package/scripts/notices/runtime-4108245a1f2df9d4e94d.txt +25 -0
- package/scripts/notices/runtime-4455bf75a91154108304.txt +21 -0
- package/scripts/notices/runtime-553fffcd9b1cb158bc3e.txt +13 -0
- package/scripts/notices/runtime-62c7a1e35f56406896d7.txt +176 -0
- package/scripts/notices/runtime-6485b8ed310d3f0340bf.txt +25 -0
- package/scripts/notices/runtime-69fef7b0f322a6555415.txt +201 -0
- package/scripts/notices/runtime-6df43f6f4b5d4587f3d8.txt +187 -0
- package/scripts/notices/runtime-799e9ca9d179295ef372.txt +24 -0
- package/scripts/notices/runtime-7b63ecd5f1902af1b637.txt +25 -0
- package/scripts/notices/runtime-7bc7d5de2a0b793d4e1a.txt +21 -0
- package/scripts/notices/runtime-7e12e5df4bae12cb2158.txt +24 -0
- package/scripts/notices/runtime-861399f8c21c042b1105.txt +12 -0
- package/scripts/notices/runtime-8ada45cd9f843acf64e4.txt +201 -0
- package/scripts/notices/runtime-90eb64f0279b0d9432ac.txt +12 -0
- package/scripts/notices/runtime-a60eea817514531668d7.txt +201 -0
- package/scripts/notices/runtime-a7c936ff1ed8fa340172.txt +25 -0
- package/scripts/notices/runtime-ab6eec6caf0fa5775e41.txt +275 -0
- package/scripts/notices/runtime-b1181a40b2a7b25cf66f.txt +19 -0
- package/scripts/notices/runtime-b71bd43a069ca0641a9e.txt +25 -0
- package/scripts/notices/runtime-c16f8dcf1a368b83be78.txt +201 -0
- package/scripts/notices/runtime-c2cfccb812fe482101a8.txt +21 -0
- package/scripts/notices/runtime-e99d88d232bf57d70f0f.txt +25 -0
- package/scripts/notices/runtime-f32fb3b417a194167cfa.txt +9 -0
- package/scripts/notices/runtime-f5062c9a188d81dfe66b.txt +39 -0
- package/scripts/notices/runtime-f9070a832833fa7488fd.txt +4 -0
- package/scripts/notices/runtime-fab3dd6bdab226f1c086.txt +373 -0
- package/scripts/notices/runtime-fba3318d0c600380177e.txt +62 -0
- package/scripts/notices/runtime-ff8f68cb076caf8cefe7.txt +25 -0
- package/scripts/notices/runtime-ff92bed461f50338dd70.txt +74 -0
- package/scripts/notices/runtime.json +1632 -0
- package/scripts/notices/sources.json +555 -0
- package/scripts/notices/xray-MIT.txt +21 -0
- package/src/attributes.ts +271 -0
- package/src/codec.ts +74 -0
- package/src/dom.ts +87 -0
- package/src/extract-plan.ts +97 -0
- package/src/extract.ts +130 -0
- package/src/hooks.ts +220 -0
- package/src/index.ts +223 -0
- package/src/io.ts +491 -0
- package/src/native.ts +135 -0
- package/src/nodes.ts +290 -0
- package/src/parse.ts +53 -0
- package/src/parser-types.ts +157 -0
- package/src/router.ts +327 -0
- package/src/selection.ts +566 -0
- package/src/slim.ts +12 -0
- package/src/transport.ts +104 -0
- package/src/types.ts +186 -0
- package/src/utils.ts +29 -0
- package/src/workers.ts +21 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +16 -0
package/src/transport.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { decodeJson, decodeString, encodeJson, encodeOptions, encodeString } from './codec.js';
|
|
2
|
+
import type { NativeBinding, NativeDocument } from './native.js';
|
|
3
|
+
|
|
4
|
+
interface TransportRegistry {
|
|
5
|
+
documents: WeakMap<object, NativeDocument>;
|
|
6
|
+
originals: WeakMap<object, NativeDocument>;
|
|
7
|
+
userErrors: WeakSet<object>;
|
|
8
|
+
}
|
|
9
|
+
const registryKey = Symbol.for('rusteerio.native-transport.v1');
|
|
10
|
+
const globals = globalThis as typeof globalThis & { [key: symbol]: TransportRegistry | undefined };
|
|
11
|
+
const registry = globals[registryKey] ??= { documents: new WeakMap(), originals: new WeakMap(), userErrors: new WeakSet() };
|
|
12
|
+
|
|
13
|
+
/** Keep the codec at the private addon boundary, including callback RPC. */
|
|
14
|
+
export function wrapNativeBinding(binding: NativeBinding): NativeBinding {
|
|
15
|
+
const raw = binding as NativeBinding & Record<string, any>;
|
|
16
|
+
const { documents, originals, userErrors } = registry;
|
|
17
|
+
const restoreError = (error: unknown): never => {
|
|
18
|
+
if (error instanceof Error && !userErrors.has(error)) {
|
|
19
|
+
const message = decodeString(error.message);
|
|
20
|
+
if (message !== error.message) {
|
|
21
|
+
const stack = error.stack;
|
|
22
|
+
error.message = message;
|
|
23
|
+
if (stack) error.stack = decodeString(stack);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
};
|
|
28
|
+
const invoke = <T>(call: () => T): T => {
|
|
29
|
+
try {
|
|
30
|
+
const result = call();
|
|
31
|
+
return result instanceof Promise ? result.catch(restoreError) as T : result;
|
|
32
|
+
} catch (error) { return restoreError(error); }
|
|
33
|
+
};
|
|
34
|
+
const wrapBridge = (bridge: (request: string) => string) => (request: string): string => {
|
|
35
|
+
try { return encodeJson(bridge(decodeJson(request))); }
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error !== null && (typeof error === 'object' || typeof error === 'function')) userErrors.add(error);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const jsonMethods = new Set(['op', 'node', 'exportTree', 'parserDiagnostics', 'adopt']);
|
|
42
|
+
const wrapDocument = (document: NativeDocument): NativeDocument => {
|
|
43
|
+
const cached = documents.get(document);
|
|
44
|
+
if (cached) return cached;
|
|
45
|
+
const methods = new Map<PropertyKey, unknown>();
|
|
46
|
+
const wrapped = new Proxy(document, {
|
|
47
|
+
get(target, property) {
|
|
48
|
+
const value = Reflect.get(target, property, target);
|
|
49
|
+
if (typeof value !== 'function') return value;
|
|
50
|
+
if (property === 'constructor') return value;
|
|
51
|
+
if (methods.has(property)) return methods.get(property);
|
|
52
|
+
const method = (...input: any[]) => invoke(() => {
|
|
53
|
+
const args = input.slice();
|
|
54
|
+
if (property === 'op') args[1] = encodeJson(args[1]);
|
|
55
|
+
else if (property === 'create') { args[0] = encodeString(args[0]); if (typeof args[2] === 'string') args[2] = encodeOptions(args[2]); }
|
|
56
|
+
else if (property === 'select' || property === 'matches') args[0] = encodeString(args[0]);
|
|
57
|
+
else if (property === 'attr') args[1] = encodeString(args[1]);
|
|
58
|
+
else if (property === 'adopt') args[0] = originals.get(args[0]) ?? args[0];
|
|
59
|
+
const result = Reflect.apply(value, target, args);
|
|
60
|
+
if (property === 'op' && args[0] === 'serialize' && typeof result === 'string' && result.startsWith('{')) {
|
|
61
|
+
const error = JSON.parse(result).__nativeError;
|
|
62
|
+
if (error?.name === 'URIError') throw new URIError(error.message);
|
|
63
|
+
}
|
|
64
|
+
return typeof result === 'string' ? jsonMethods.has(String(property)) ? decodeJson(result) : decodeString(result) : result;
|
|
65
|
+
});
|
|
66
|
+
methods.set(property, method);
|
|
67
|
+
return method;
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
documents.set(document, wrapped);
|
|
71
|
+
originals.set(wrapped, document);
|
|
72
|
+
return wrapped;
|
|
73
|
+
};
|
|
74
|
+
const wrapStream = (stream: any) => {
|
|
75
|
+
let carry = '';
|
|
76
|
+
return {
|
|
77
|
+
async write(chunk: string) {
|
|
78
|
+
let source = carry + chunk;
|
|
79
|
+
carry = '';
|
|
80
|
+
const last = source.charCodeAt(source.length - 1);
|
|
81
|
+
if (last >= 0xd800 && last <= 0xdbff) { carry = source.slice(-1); source = source.slice(0, -1); }
|
|
82
|
+
if (source) await invoke(() => stream.write(encodeString(source)));
|
|
83
|
+
},
|
|
84
|
+
async finish() {
|
|
85
|
+
if (carry) { const final = carry; carry = ''; await invoke(() => stream.write(encodeString(final))); }
|
|
86
|
+
return wrapDocument(await invoke(() => stream.finish()));
|
|
87
|
+
},
|
|
88
|
+
abort() { carry = ''; return invoke(() => stream.abort()); },
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
const wrapConstructor = (Constructor: any, argumentsFor: (args: any[]) => any[], wrap: (value: any) => any) => new Proxy(Constructor, {
|
|
92
|
+
construct(target, args) { return wrap(invoke(() => Reflect.construct(target, argumentsFor(args)))); },
|
|
93
|
+
});
|
|
94
|
+
const wrapped: NativeBinding & Record<string, any> = { ...raw };
|
|
95
|
+
wrapped.NativeDocument = wrapConstructor(raw.NativeDocument, ([html, isDocument, options]) => [encodeString(html), isDocument, encodeOptions(options)], wrapDocument);
|
|
96
|
+
if (raw.NativeStream) wrapped.NativeStream = wrapConstructor(raw.NativeStream, ([options, isDocument, bridge]) => [encodeOptions(options), isDocument, bridge && wrapBridge(bridge)], wrapStream);
|
|
97
|
+
if (raw.NativeHookStream) wrapped.NativeHookStream = wrapConstructor(raw.NativeHookStream, ([isDocument, options, bridge]) => [isDocument, encodeOptions(options), wrapBridge(bridge)], wrapStream);
|
|
98
|
+
if (raw.parseWithTreeAdapter) wrapped.parseWithTreeAdapter = (source: string, isDocument: boolean, options: string, bridge: (request: string) => string) => wrapDocument(invoke(() => raw.parseWithTreeAdapter(encodeString(source), isDocument, encodeOptions(options), wrapBridge(bridge))));
|
|
99
|
+
if (raw.parseAsync) wrapped.parseAsync = async (source, isDocument, options) => wrapDocument(await invoke(() => raw.parseAsync!(encodeString(source), isDocument, encodeOptions(options))));
|
|
100
|
+
if (raw.parseManyAsync) wrapped.parseManyAsync = async (sources, isDocument, threads, options) => (await invoke(() => raw.parseManyAsync!(sources.map(encodeString), isDocument, threads, encodeOptions(options)))).map(wrapDocument);
|
|
101
|
+
if (raw.extractPlanManyAsync) wrapped.extractPlanManyAsync = async (sources, plan, threads, options) => decodeJson(await invoke(() => raw.extractPlanManyAsync!(sources.map(encodeString), encodeJson(plan), threads, encodeOptions(options))));
|
|
102
|
+
if (raw.extractManyAsync) wrapped.extractManyAsync = async (sources, queries, threads, isDocument, options) => decodeJson(await invoke(() => raw.extractManyAsync!(sources.map(encodeString), queries.map((query) => ({ ...query, key: encodeString(query.key), selector: encodeString(query.selector), ...(query.attr === undefined ? {} : { attr: encodeString(query.attr) }) })), threads, isDocument, encodeOptions(options))));
|
|
103
|
+
return wrapped;
|
|
104
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { Cheerio } from './selection.js';
|
|
2
|
+
import type { ParserErrorHandler, TreeAdapter, TokenizerConstructor } from './parser-types.js';
|
|
3
|
+
export type * from './parser-types.js';
|
|
4
|
+
|
|
5
|
+
/** DOM-compatible views over stable nodes owned by the native document. */
|
|
6
|
+
export declare enum ElementType {
|
|
7
|
+
Root = 'root', Text = 'text', Directive = 'directive', Comment = 'comment',
|
|
8
|
+
Script = 'script', Style = 'style', Tag = 'tag', CDATA = 'cdata', Doctype = 'doctype',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SourceCodeLocation {
|
|
12
|
+
startLine: number; startCol: number; startOffset: number;
|
|
13
|
+
endLine: number; endCol: number; endOffset: number;
|
|
14
|
+
}
|
|
15
|
+
export interface TagSourceCodeLocation extends SourceCodeLocation { startTag?: SourceCodeLocation; endTag?: SourceCodeLocation; attrs?: Record<string, SourceCodeLocation> }
|
|
16
|
+
|
|
17
|
+
export interface Node {
|
|
18
|
+
readonly type: ElementType;
|
|
19
|
+
parent: ParentNode | null;
|
|
20
|
+
prev: ChildNode | null;
|
|
21
|
+
next: ChildNode | null;
|
|
22
|
+
startIndex: number | null;
|
|
23
|
+
endIndex: number | null;
|
|
24
|
+
readonly nodeType: number;
|
|
25
|
+
parentNode: ParentNode | null;
|
|
26
|
+
previousSibling: ChildNode | null;
|
|
27
|
+
nextSibling: ChildNode | null;
|
|
28
|
+
sourceCodeLocation?: SourceCodeLocation | null;
|
|
29
|
+
cloneNode<T extends Node>(this: T, recursive?: boolean): T;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface DataNode extends Node { data: string; nodeValue: string }
|
|
33
|
+
export interface Text extends DataNode { type: ElementType.Text; readonly nodeType: 3 }
|
|
34
|
+
export interface Comment extends DataNode { type: ElementType.Comment; readonly nodeType: 8 }
|
|
35
|
+
export interface ProcessingInstruction extends DataNode {
|
|
36
|
+
type: ElementType.Directive;
|
|
37
|
+
name: string;
|
|
38
|
+
readonly nodeType: 1;
|
|
39
|
+
'x-name'?: string;
|
|
40
|
+
'x-publicId'?: string;
|
|
41
|
+
'x-systemId'?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface NodeWithChildren extends Node {
|
|
44
|
+
children: ChildNode[];
|
|
45
|
+
childNodes: ChildNode[];
|
|
46
|
+
readonly firstChild: ChildNode | null;
|
|
47
|
+
readonly lastChild: ChildNode | null;
|
|
48
|
+
}
|
|
49
|
+
export interface Document extends NodeWithChildren { type: ElementType.Root; readonly nodeType: 9; 'x-mode'?: 'quirks' | 'limited-quirks' | 'no-quirks' }
|
|
50
|
+
export interface CDATA extends NodeWithChildren { type: ElementType.CDATA; readonly nodeType: 4 }
|
|
51
|
+
export interface Element extends NodeWithChildren {
|
|
52
|
+
type: ElementType.Tag | ElementType.Script | ElementType.Style;
|
|
53
|
+
readonly nodeType: 1;
|
|
54
|
+
name: string;
|
|
55
|
+
tagName: string;
|
|
56
|
+
attribs: Record<string, string>;
|
|
57
|
+
namespace?: string;
|
|
58
|
+
sourceCodeLocation?: TagSourceCodeLocation | null;
|
|
59
|
+
readonly attributes: { name: string; value: string; namespace?: string; prefix?: string }[];
|
|
60
|
+
'x-attribsNamespace'?: Record<string, string>;
|
|
61
|
+
'x-attribsPrefix'?: Record<string, string>;
|
|
62
|
+
}
|
|
63
|
+
export type ParentNode = Document | Element | CDATA;
|
|
64
|
+
export type ChildNode = Text | Comment | ProcessingInstruction | Element | CDATA | Document;
|
|
65
|
+
export type AnyNode = ParentNode | ChildNode;
|
|
66
|
+
|
|
67
|
+
export interface HTMLParser2Options {
|
|
68
|
+
xmlMode?: boolean;
|
|
69
|
+
decodeEntities?: boolean;
|
|
70
|
+
encodeEntities?: boolean | 'utf8';
|
|
71
|
+
lowerCaseTags?: boolean;
|
|
72
|
+
lowerCaseAttributeNames?: boolean;
|
|
73
|
+
recognizeCDATA?: boolean;
|
|
74
|
+
recognizeSelfClosing?: boolean;
|
|
75
|
+
withStartIndices?: boolean;
|
|
76
|
+
withEndIndices?: boolean;
|
|
77
|
+
emptyAttrs?: boolean;
|
|
78
|
+
selfClosingTags?: boolean;
|
|
79
|
+
Tokenizer?: TokenizerConstructor;
|
|
80
|
+
[key: string]: any;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface CheerioOptions extends HTMLParser2Options {
|
|
84
|
+
xml?: boolean | HTMLParser2Options;
|
|
85
|
+
baseURI?: string | URL;
|
|
86
|
+
quirksMode?: boolean;
|
|
87
|
+
scriptingEnabled?: boolean;
|
|
88
|
+
sourceCodeLocationInfo?: boolean;
|
|
89
|
+
treeAdapter?: TreeAdapter;
|
|
90
|
+
onParseError?: ParserErrorHandler | null;
|
|
91
|
+
pseudos?: Record<string, string | ((element: Element, value?: string | null) => boolean)>;
|
|
92
|
+
_useHtmlParser2?: boolean;
|
|
93
|
+
}
|
|
94
|
+
export type InternalOptions = CheerioOptions;
|
|
95
|
+
|
|
96
|
+
type LowercaseLetters = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
|
|
97
|
+
type AlphaNumeric = LowercaseLetters | Uppercase<LowercaseLetters> | `${number}`;
|
|
98
|
+
export type SelectorType = `${'.' | '#' | ':' | '|' | '>' | '+' | '~' | '['}${AlphaNumeric}${string}` | `${AlphaNumeric}${string}`;
|
|
99
|
+
export type BasicAcceptedElems<T extends AnyNode = AnyNode> = ArrayLike<T> | T | string;
|
|
100
|
+
export type AcceptedElems<T extends AnyNode = AnyNode> = BasicAcceptedElems<T> | ((this: T, index: number, element: T) => BasicAcceptedElems<T>);
|
|
101
|
+
export type FilterFunction<T> = (this: T, index: number, element: T) => boolean;
|
|
102
|
+
export type AcceptedFilters<T> = string | FilterFunction<T> | T | Cheerio<T>;
|
|
103
|
+
export type LoadContent = string | Buffer | AnyNode | ArrayLike<AnyNode>;
|
|
104
|
+
|
|
105
|
+
export interface CheerioAPI {
|
|
106
|
+
<T extends AnyNode, S extends string>(
|
|
107
|
+
selector?: S | BasicAcceptedElems<T>,
|
|
108
|
+
context?: BasicAcceptedElems<AnyNode> | null,
|
|
109
|
+
root?: BasicAcceptedElems<Document>,
|
|
110
|
+
options?: CheerioOptions,
|
|
111
|
+
): Cheerio<S extends SelectorType ? Element : T>;
|
|
112
|
+
<T extends AnyNode, S extends string>(
|
|
113
|
+
selector?: S | BasicAcceptedElems<T>,
|
|
114
|
+
context?: BasicAcceptedElems<AnyNode> | null,
|
|
115
|
+
root?: BasicAcceptedElems<Document>,
|
|
116
|
+
options?: CheerioOptions,
|
|
117
|
+
): Cheerio<AnyNode>;
|
|
118
|
+
html(options?: CheerioOptions): string;
|
|
119
|
+
html(dom?: BasicAcceptedElems<AnyNode> | Cheerio<AnyNode>, options?: CheerioOptions): string;
|
|
120
|
+
xml(dom?: BasicAcceptedElems<AnyNode> | Cheerio<AnyNode>): string;
|
|
121
|
+
text(elements?: ArrayLike<AnyNode>): string;
|
|
122
|
+
root(): Cheerio<Document>;
|
|
123
|
+
contains(container: AnyNode, contained: AnyNode): boolean;
|
|
124
|
+
merge<T>(first: ArrayLike<T>, second: ArrayLike<T>): ArrayLike<T> | undefined;
|
|
125
|
+
parseHTML(data: string, context?: unknown, keepScripts?: boolean): AnyNode[];
|
|
126
|
+
parseHTML(data?: '' | null): null;
|
|
127
|
+
load(content: LoadContent, options?: CheerioOptions | null, isDocument?: boolean): CheerioAPI;
|
|
128
|
+
extract<M extends ExtractMap>(this: CheerioAPI, map: M): ExtractedMap<M>;
|
|
129
|
+
extract<M extends ExtractMap>(this: CheerioAPI, map: M): Record<string, unknown>;
|
|
130
|
+
fn: typeof Cheerio.prototype;
|
|
131
|
+
_root: Document;
|
|
132
|
+
_options: InternalOptions;
|
|
133
|
+
[key: string]: any;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type ExtractDescriptorFn = (element: Element, key: string, result: Record<string, unknown>) => unknown;
|
|
137
|
+
export interface ExtractDescriptor {
|
|
138
|
+
selector: string;
|
|
139
|
+
value?: string | ExtractDescriptorFn | ExtractMap;
|
|
140
|
+
}
|
|
141
|
+
type ExtractValue = string | ExtractDescriptor | [string | ExtractDescriptor];
|
|
142
|
+
export type ExtractMap = Record<string, ExtractValue>;
|
|
143
|
+
export type ExtractedValue<V extends ExtractValue> = V extends [string | ExtractDescriptor]
|
|
144
|
+
? NonNullable<ExtractedValue<V[0]>>[]
|
|
145
|
+
: V extends string ? string | undefined
|
|
146
|
+
: V extends ExtractDescriptor ? V['value'] extends infer U
|
|
147
|
+
? U extends ExtractMap ? ExtractedMap<U> | undefined
|
|
148
|
+
: U extends ExtractDescriptorFn ? ReturnType<U> | undefined
|
|
149
|
+
: string | undefined
|
|
150
|
+
: never
|
|
151
|
+
: never;
|
|
152
|
+
export type ExtractedMap<M extends ExtractMap> = {
|
|
153
|
+
[key in keyof M]: ExtractedValue<M[key]>;
|
|
154
|
+
};
|
|
155
|
+
export type ExtractionDescriptor = ExtractDescriptor;
|
|
156
|
+
export type ExtractionMap = ExtractMap;
|
|
157
|
+
export type ExtractionResult<M extends ExtractMap> = ExtractedMap<M>;
|
|
158
|
+
|
|
159
|
+
export interface EncodingOptions { defaultEncoding?: string; transportLayerEncodingLabel?: string | null; userEncoding?: string; maxBytes?: number }
|
|
160
|
+
export interface DecodeStreamOptions extends CheerioOptions { encoding?: EncodingOptions }
|
|
161
|
+
/** Structural Node/Undici FormData compatibility without importing its package. */
|
|
162
|
+
export interface FormDataLike extends Iterable<[string, string | import('node:buffer').Blob]> {
|
|
163
|
+
append(name: string, value: unknown, filename?: string): void;
|
|
164
|
+
get(name: string): string | import('node:buffer').Blob | null;
|
|
165
|
+
}
|
|
166
|
+
export interface CheerioRequestOptions extends DecodeStreamOptions {
|
|
167
|
+
requestOptions?: {
|
|
168
|
+
method?: string;
|
|
169
|
+
headers?: Record<string, string | string[] | undefined> | string[] | Iterable<[string, string | string[] | undefined]> | Headers | null;
|
|
170
|
+
body?: string | Buffer | Uint8Array | import('node:stream').Readable | FormData | FormDataLike | null;
|
|
171
|
+
query?: import('node:querystring').ParsedUrlQueryInput;
|
|
172
|
+
onInfo?: (info: { statusCode: number; headers: Record<string, string | string[]> }) => void;
|
|
173
|
+
reset?: boolean;
|
|
174
|
+
typeOfService?: number | null;
|
|
175
|
+
highWaterMark?: number;
|
|
176
|
+
maxRedirections?: number;
|
|
177
|
+
throwOnError?: boolean;
|
|
178
|
+
signal?: unknown;
|
|
179
|
+
headersTimeout?: number | null;
|
|
180
|
+
bodyTimeout?: number | null;
|
|
181
|
+
dispatcher?: unknown;
|
|
182
|
+
[key: string]: unknown;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
export interface ParallelOptions extends CheerioOptions { threads?: number }
|
|
186
|
+
export type SerializedField = { name: string; value: string };
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AnyNode, Element } from './types.js';
|
|
2
|
+
import type { Cheerio } from './selection.js';
|
|
3
|
+
|
|
4
|
+
export function isCheerio(value: unknown): value is Cheerio<AnyNode> {
|
|
5
|
+
return value !== null && typeof value === 'object' && 'cheerio' in value;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function camelCase(value: string): string {
|
|
9
|
+
return value.replace(/[._-](\w|$)/g, (_match, character: string) => character.toUpperCase());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function cssCase(value: string): string {
|
|
13
|
+
return value.replace(/[A-Z]/g, (character) => `-${character.toLowerCase()}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function domEach<T, A extends ArrayLike<T>>(array: A, callback: (element: T, index: number) => void): A {
|
|
17
|
+
for (let index = 0; index < array.length; index += 1) callback(array[index], index);
|
|
18
|
+
return array;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isHtml(value: unknown): value is string {
|
|
22
|
+
if (typeof value !== 'string') return false;
|
|
23
|
+
const start = value.indexOf('<');
|
|
24
|
+
return start >= 0 && /[A-Za-z!]/.test(value[start + 1] ?? '') && value.indexOf('>', start + 2) >= 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isTag(node: AnyNode): node is Element {
|
|
28
|
+
return node.type === 'tag' || node.type === 'script' || node.type === 'style';
|
|
29
|
+
}
|
package/src/workers.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { requireNative, type NativeWorkerPoolInfo } from './native.js';
|
|
2
|
+
|
|
3
|
+
export interface WorkerOptions { threads: number }
|
|
4
|
+
export type WorkerPoolInfo = NativeWorkerPoolInfo;
|
|
5
|
+
|
|
6
|
+
/** Set the process-wide native CPU-worker budget before starting async work. */
|
|
7
|
+
export function configureWorkers(options: WorkerOptions | number): WorkerPoolInfo {
|
|
8
|
+
const threads = typeof options === 'number' ? options : options?.threads;
|
|
9
|
+
if (!Number.isSafeInteger(threads) || threads < 1 || threads > 256) throw new RangeError('threads must be an integer from 1 to 256');
|
|
10
|
+
const binding = requireNative();
|
|
11
|
+
if (!binding.configureWorkerPool || !binding.workerPoolInfo) throw new Error('This native build does not support a shared worker pool');
|
|
12
|
+
binding.configureWorkerPool(threads);
|
|
13
|
+
return binding.workerPoolInfo();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Observe the configured budget and actual concurrent native CPU work. */
|
|
17
|
+
export function workerPoolInfo(): WorkerPoolInfo {
|
|
18
|
+
const binding = requireNative();
|
|
19
|
+
if (!binding.workerPoolInfo) throw new Error('This native build does not support worker pool diagnostics');
|
|
20
|
+
return binding.workerPoolInfo();
|
|
21
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"stripInternal": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"types": ["node"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts", "tsup.config.ts"]
|
|
15
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: ['src/index.ts', 'src/slim.ts', 'src/utils.ts'],
|
|
5
|
+
format: ['cjs', 'esm'],
|
|
6
|
+
outExtension({ format }) { return { js: format === 'esm' ? '.mjs' : '.cjs' }; },
|
|
7
|
+
target: 'node20',
|
|
8
|
+
platform: 'node',
|
|
9
|
+
dts: true,
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
clean: true,
|
|
12
|
+
esbuildOptions(options) {
|
|
13
|
+
// The CommonJS loader uses __dirname, so its import.meta branch is dead.
|
|
14
|
+
options.logOverride = { 'empty-import-meta': 'silent' };
|
|
15
|
+
},
|
|
16
|
+
});
|