@salve-software/react-native-nitro-jsdom 1.0.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/LICENSE +21 -0
- package/NitroJsdom.podspec +63 -0
- package/README.md +95 -0
- package/android/CMakeLists.txt +86 -0
- package/android/build.gradle +148 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +9 -0
- package/android/src/main/java/com/nitrojsdom/NitroJsdomPackage.kt +20 -0
- package/cpp/HybridHtmlSandbox.cpp +171 -0
- package/cpp/HybridHtmlSandbox.hpp +47 -0
- package/cpp/lexbor/LexborDocument.cpp +365 -0
- package/cpp/lexbor/LexborDocument.hpp +71 -0
- package/cpp/quickjs/DOMBindings.cpp +57 -0
- package/cpp/quickjs/DOMBindings.hpp +21 -0
- package/cpp/quickjs/DOMBindingsInternal.cpp +157 -0
- package/cpp/quickjs/DOMBindingsInternal.hpp +83 -0
- package/cpp/quickjs/MutationObservers.cpp +546 -0
- package/cpp/quickjs/MutationObservers.hpp +127 -0
- package/cpp/quickjs/QuickJSRuntime.cpp +475 -0
- package/cpp/quickjs/QuickJSRuntime.hpp +110 -0
- package/cpp/quickjs/Storage.cpp +130 -0
- package/cpp/quickjs/Storage.hpp +40 -0
- package/cpp/quickjs/bindings/ClassListBindings.cpp +241 -0
- package/cpp/quickjs/bindings/ClassListBindings.hpp +29 -0
- package/cpp/quickjs/bindings/DatasetBindings.cpp +120 -0
- package/cpp/quickjs/bindings/DatasetBindings.hpp +20 -0
- package/cpp/quickjs/bindings/DocumentBindings.cpp +155 -0
- package/cpp/quickjs/bindings/DocumentBindings.hpp +19 -0
- package/cpp/quickjs/bindings/ElementBindings.cpp +1106 -0
- package/cpp/quickjs/bindings/ElementBindings.hpp +19 -0
- package/cpp/quickjs/bindings/EventBindings.cpp +352 -0
- package/cpp/quickjs/bindings/EventBindings.hpp +21 -0
- package/cpp/quickjs/bindings/FetchBindings.cpp +347 -0
- package/cpp/quickjs/bindings/FetchBindings.hpp +16 -0
- package/cpp/quickjs/bindings/StyleBindings.cpp +245 -0
- package/cpp/quickjs/bindings/StyleBindings.hpp +22 -0
- package/cpp/quickjs/bindings/TimerBindings.cpp +94 -0
- package/cpp/quickjs/bindings/TimerBindings.hpp +16 -0
- package/cpp/quickjs/bindings/WindowBindings.cpp +211 -0
- package/cpp/quickjs/bindings/WindowBindings.hpp +16 -0
- package/ios/Bridge.h +8 -0
- package/lib/commonjs/classes/JSDOM/JSDOM.class.js +138 -0
- package/lib/commonjs/classes/JSDOM/JSDOM.class.js.map +1 -0
- package/lib/commonjs/classes/JSDOM/index.js +17 -0
- package/lib/commonjs/classes/JSDOM/index.js.map +1 -0
- package/lib/commonjs/classes/JSDOM/types/IFetchOptions.js +2 -0
- package/lib/commonjs/classes/JSDOM/types/IFetchOptions.js.map +1 -0
- package/lib/commonjs/classes/JSDOM/types/IJSDOMOptions.js +6 -0
- package/lib/commonjs/classes/JSDOM/types/IJSDOMOptions.js.map +1 -0
- package/lib/commonjs/classes/JSDOM/types/index.js +2 -0
- package/lib/commonjs/classes/JSDOM/types/index.js.map +1 -0
- package/lib/commonjs/classes/index.js +17 -0
- package/lib/commonjs/classes/index.js.map +1 -0
- package/lib/commonjs/index.js +17 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/specs/HtmlSandbox.nitro.js +6 -0
- package/lib/commonjs/specs/HtmlSandbox.nitro.js.map +1 -0
- package/lib/module/classes/JSDOM/JSDOM.class.js +133 -0
- package/lib/module/classes/JSDOM/JSDOM.class.js.map +1 -0
- package/lib/module/classes/JSDOM/index.js +4 -0
- package/lib/module/classes/JSDOM/index.js.map +1 -0
- package/lib/module/classes/JSDOM/types/IFetchOptions.js +2 -0
- package/lib/module/classes/JSDOM/types/IFetchOptions.js.map +1 -0
- package/lib/module/classes/JSDOM/types/IJSDOMOptions.js +4 -0
- package/lib/module/classes/JSDOM/types/IJSDOMOptions.js.map +1 -0
- package/lib/module/classes/JSDOM/types/index.js +2 -0
- package/lib/module/classes/JSDOM/types/index.js.map +1 -0
- package/lib/module/classes/index.js +4 -0
- package/lib/module/classes/index.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/specs/HtmlSandbox.nitro.js +4 -0
- package/lib/module/specs/HtmlSandbox.nitro.js.map +1 -0
- package/lib/typescript/src/classes/JSDOM/JSDOM.class.d.ts +74 -0
- package/lib/typescript/src/classes/JSDOM/JSDOM.class.d.ts.map +1 -0
- package/lib/typescript/src/classes/JSDOM/index.d.ts +3 -0
- package/lib/typescript/src/classes/JSDOM/index.d.ts.map +1 -0
- package/lib/typescript/src/classes/JSDOM/types/IFetchOptions.d.ts +14 -0
- package/lib/typescript/src/classes/JSDOM/types/IFetchOptions.d.ts.map +1 -0
- package/lib/typescript/src/classes/JSDOM/types/IJSDOMOptions.d.ts +57 -0
- package/lib/typescript/src/classes/JSDOM/types/IJSDOMOptions.d.ts.map +1 -0
- package/lib/typescript/src/classes/JSDOM/types/index.d.ts +3 -0
- package/lib/typescript/src/classes/JSDOM/types/index.d.ts.map +1 -0
- package/lib/typescript/src/classes/index.d.ts +2 -0
- package/lib/typescript/src/classes/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/specs/HtmlSandbox.nitro.d.ts +13 -0
- package/lib/typescript/src/specs/HtmlSandbox.nitro.d.ts.map +1 -0
- package/nitro.json +26 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NitroJsdom+autolinking.cmake +81 -0
- package/nitrogen/generated/android/NitroJsdom+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroJsdomOnLoad.cpp +49 -0
- package/nitrogen/generated/android/NitroJsdomOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrojsdom/NitroJsdomOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NitroJsdom+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NitroJsdom-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/NitroJsdom-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NitroJsdom-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/NitroJsdomAutolinking.mm +35 -0
- package/nitrogen/generated/ios/NitroJsdomAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/HybridHtmlSandboxSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridHtmlSandboxSpec.hpp +73 -0
- package/package.json +131 -0
- package/src/classes/JSDOM/JSDOM.class.ts +145 -0
- package/src/classes/JSDOM/index.ts +2 -0
- package/src/classes/JSDOM/types/IFetchOptions.ts +14 -0
- package/src/classes/JSDOM/types/IJSDOMOptions.ts +57 -0
- package/src/classes/JSDOM/types/index.ts +2 -0
- package/src/classes/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/specs/HtmlSandbox.nitro.ts +33 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#include "DOMBindingsInternal.hpp"
|
|
2
|
+
#include "QuickJSRuntime.hpp"
|
|
3
|
+
#include "../lexbor/LexborDocument.hpp"
|
|
4
|
+
#include <lexbor/html/html.h>
|
|
5
|
+
#include <lexbor/dom/dom.h>
|
|
6
|
+
#include <cctype>
|
|
7
|
+
#include <sstream>
|
|
8
|
+
|
|
9
|
+
namespace margelo::nitro::nitrojsdom {
|
|
10
|
+
|
|
11
|
+
JSClassID js_element_class_id = 0;
|
|
12
|
+
JSClassID js_node_class_id = 0;
|
|
13
|
+
|
|
14
|
+
namespace {
|
|
15
|
+
JSClassDef js_element_class = { "Element", .finalizer = nullptr };
|
|
16
|
+
} // namespace
|
|
17
|
+
|
|
18
|
+
JSValue make_element(JSContext* ctx, void* ptr) {
|
|
19
|
+
if (!ptr) return JS_NULL;
|
|
20
|
+
|
|
21
|
+
RuntimeContext* rctx = get_ctx(ctx);
|
|
22
|
+
if (rctx) {
|
|
23
|
+
auto it = rctx->node_wrapper_cache.find(ptr);
|
|
24
|
+
if (it != rctx->node_wrapper_cache.end()) {
|
|
25
|
+
JSValue* cached = static_cast<JSValue*>(it->second);
|
|
26
|
+
return JS_DupValue(ctx, *cached);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
lxb_dom_node_t* node = static_cast<lxb_dom_node_t*>(ptr);
|
|
31
|
+
JSValue obj;
|
|
32
|
+
if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
|
|
33
|
+
obj = JS_NewObjectClass(ctx, js_element_class_id);
|
|
34
|
+
} else {
|
|
35
|
+
obj = JS_NewObjectClass(ctx, js_node_class_id);
|
|
36
|
+
}
|
|
37
|
+
JS_SetOpaque(obj, ptr);
|
|
38
|
+
|
|
39
|
+
if (rctx) {
|
|
40
|
+
rctx->node_wrapper_cache[ptr] = new JSValue(JS_DupValue(ctx, obj));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void invalidate_node_cache(JSContext* ctx, RuntimeContext* rctx, void* node) {
|
|
47
|
+
if (!rctx || !node) return;
|
|
48
|
+
auto it = rctx->node_wrapper_cache.find(node);
|
|
49
|
+
if (it != rctx->node_wrapper_cache.end()) {
|
|
50
|
+
JSValue* v = static_cast<JSValue*>(it->second);
|
|
51
|
+
JS_SetOpaque(*v, nullptr);
|
|
52
|
+
JS_FreeValue(ctx, *v);
|
|
53
|
+
delete v;
|
|
54
|
+
rctx->node_wrapper_cache.erase(it);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void invalidate_node_cache_batch(JSContext* ctx, RuntimeContext* rctx, const std::vector<void*>& nodes) {
|
|
59
|
+
for (void* n : nodes) invalidate_node_cache(ctx, rctx, n);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void clear_node_cache(JSContext* ctx, RuntimeContext* rctx) {
|
|
63
|
+
if (!rctx) return;
|
|
64
|
+
for (auto& kv : rctx->node_wrapper_cache) {
|
|
65
|
+
JSValue* v = static_cast<JSValue*>(kv.second);
|
|
66
|
+
JS_SetOpaque(*v, nullptr);
|
|
67
|
+
JS_FreeValue(ctx, *v);
|
|
68
|
+
delete v;
|
|
69
|
+
}
|
|
70
|
+
rctx->node_wrapper_cache.clear();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
JSValue make_element_array(JSContext* ctx, const std::vector<void*>& elements) {
|
|
74
|
+
JSValue arr = JS_NewArray(ctx);
|
|
75
|
+
for (size_t i = 0; i < elements.size(); i++)
|
|
76
|
+
JS_SetPropertyUint32(ctx, arr, (uint32_t)i, make_element(ctx, elements[i]));
|
|
77
|
+
return arr;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
lxb_dom_element_t* unwrap_element(JSContext* ctx, JSValue val) {
|
|
81
|
+
return static_cast<lxb_dom_element_t*>(JS_GetOpaque(val, js_element_class_id));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
lxb_dom_node_t* unwrap_node(JSContext* ctx, JSValue val) {
|
|
85
|
+
void* p = JS_GetOpaque(val, js_element_class_id);
|
|
86
|
+
if (p) return static_cast<lxb_dom_node_t*>(p);
|
|
87
|
+
p = JS_GetOpaque(val, js_node_class_id);
|
|
88
|
+
return static_cast<lxb_dom_node_t*>(p);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
std::string serialize_node(lxb_dom_node_t* node) {
|
|
92
|
+
std::string result;
|
|
93
|
+
lxb_html_serialize_tree_cb(node,
|
|
94
|
+
[](const lxb_char_t* data, size_t len, void* ctx) -> lxb_status_t {
|
|
95
|
+
static_cast<std::string*>(ctx)->append(reinterpret_cast<const char*>(data), len);
|
|
96
|
+
return LXB_STATUS_OK;
|
|
97
|
+
}, &result);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
RuntimeContext* get_ctx(JSContext* ctx) {
|
|
102
|
+
return static_cast<RuntimeContext*>(JS_GetContextOpaque(ctx));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
LexborDocument* get_doc(JSContext* ctx) {
|
|
106
|
+
auto* rctx = get_ctx(ctx);
|
|
107
|
+
return rctx ? rctx->document : nullptr;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
void define_prop(JSContext* ctx, JSValue obj, const char* name, GetterFn getter, SetterFn setter) {
|
|
111
|
+
JSAtom atom = JS_NewAtom(ctx, name);
|
|
112
|
+
JSValue get_fn = JS_NewCFunction2(ctx, (JSCFunction*)getter, name, 0, JS_CFUNC_getter, 0);
|
|
113
|
+
JSValue set_fn = setter
|
|
114
|
+
? JS_NewCFunction2(ctx, (JSCFunction*)setter, name, 1, JS_CFUNC_setter, 0)
|
|
115
|
+
: JS_UNDEFINED;
|
|
116
|
+
JS_DefinePropertyGetSet(ctx, obj, atom, get_fn, set_fn, JS_PROP_CONFIGURABLE);
|
|
117
|
+
JS_FreeAtom(ctx, atom);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
bool get_bool_prop(JSContext* ctx, JSValue obj, const char* name) {
|
|
121
|
+
JSValue v = JS_GetPropertyStr(ctx, obj, name);
|
|
122
|
+
bool b = JS_ToBool(ctx, v) > 0;
|
|
123
|
+
JS_FreeValue(ctx, v);
|
|
124
|
+
return b;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
std::string classNames_to_selector(const std::string& names) {
|
|
128
|
+
std::string sel;
|
|
129
|
+
std::istringstream iss(names);
|
|
130
|
+
std::string cls;
|
|
131
|
+
while (iss >> cls) { sel += '.'; sel += cls; }
|
|
132
|
+
return sel;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// data-foo-bar -> fooBar ; background-color -> backgroundColor
|
|
136
|
+
std::string attr_suffix_to_camel(const std::string& suffix) {
|
|
137
|
+
std::string out;
|
|
138
|
+
bool upper_next = false;
|
|
139
|
+
for (char c : suffix) {
|
|
140
|
+
if (c == '-') { upper_next = true; continue; }
|
|
141
|
+
out += upper_next ? (char)std::toupper((unsigned char)c) : c;
|
|
142
|
+
upper_next = false;
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// fooBar -> foo-bar ; backgroundColor -> background-color
|
|
148
|
+
std::string camel_to_attr_suffix(const std::string& camel) {
|
|
149
|
+
std::string out;
|
|
150
|
+
for (char c : camel) {
|
|
151
|
+
if (std::isupper((unsigned char)c)) { out += '-'; out += (char)std::tolower((unsigned char)c); }
|
|
152
|
+
else out += c;
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Internal header shared across the QuickJS binding translation units
|
|
4
|
+
// (ElementBindings.cpp, DocumentBindings.cpp, EventBindings.cpp, TimerBindings.cpp,
|
|
5
|
+
// WindowBindings.cpp, FetchBindings.cpp, MutationObservers.cpp, ...).
|
|
6
|
+
//
|
|
7
|
+
// DOMBindings::install() (DOMBindings.cpp) is the only orchestrator: it calls each
|
|
8
|
+
// of the *Bindings::install(ctx) entry points in order. Everything below is the
|
|
9
|
+
// small set of helpers those entry points need from one another.
|
|
10
|
+
|
|
11
|
+
#include "quickjs.h"
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
// Forward-declared at global scope (not inside our namespace) so this matches
|
|
16
|
+
// the real lxb_dom_element_t/lxb_dom_node_t typedefs from lexbor's own headers
|
|
17
|
+
// bit-for-bit when both are included in the same translation unit.
|
|
18
|
+
struct lxb_dom_element;
|
|
19
|
+
struct lxb_dom_node;
|
|
20
|
+
typedef struct lxb_dom_element lxb_dom_element_t;
|
|
21
|
+
typedef struct lxb_dom_node lxb_dom_node_t;
|
|
22
|
+
|
|
23
|
+
namespace margelo::nitro::nitrojsdom {
|
|
24
|
+
|
|
25
|
+
struct RuntimeContext;
|
|
26
|
+
class LexborDocument;
|
|
27
|
+
|
|
28
|
+
// ── Element / Node class IDs + wrapping ──────────────────────────────────────
|
|
29
|
+
// js_element_class_id wraps lxb_dom_element_t* — real element nodes only.
|
|
30
|
+
// js_node_class_id wraps lxb_dom_node_t* — text, comment, document, etc.
|
|
31
|
+
//
|
|
32
|
+
// make_element() dispatches on the node type: Element nodes get the element
|
|
33
|
+
// class (which exposes getAttribute, classList, etc.); all other nodes get the
|
|
34
|
+
// node class (Node traversal only). This prevents non-element nodes from
|
|
35
|
+
// reaching lxb_dom_element_* calls.
|
|
36
|
+
//
|
|
37
|
+
// unwrap_element() returns non-null only for element-class objects.
|
|
38
|
+
// unwrap_node() returns non-null for either class (shared Node methods).
|
|
39
|
+
|
|
40
|
+
extern JSClassID js_element_class_id;
|
|
41
|
+
extern JSClassID js_node_class_id;
|
|
42
|
+
|
|
43
|
+
JSValue make_element(JSContext* ctx, void* node_or_el);
|
|
44
|
+
JSValue make_element_array(JSContext* ctx, const std::vector<void*>& elements);
|
|
45
|
+
lxb_dom_element_t* unwrap_element(JSContext* ctx, JSValue val);
|
|
46
|
+
lxb_dom_node_t* unwrap_node(JSContext* ctx, JSValue val);
|
|
47
|
+
std::string serialize_node(lxb_dom_node_t* node);
|
|
48
|
+
|
|
49
|
+
// ── RuntimeContext access ─────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
RuntimeContext* get_ctx(JSContext* ctx);
|
|
52
|
+
LexborDocument* get_doc(JSContext* ctx);
|
|
53
|
+
|
|
54
|
+
// ── Node wrapper cache ────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
void invalidate_node_cache(JSContext* ctx, RuntimeContext* rctx, void* node);
|
|
57
|
+
void invalidate_node_cache_batch(JSContext* ctx, RuntimeContext* rctx, const std::vector<void*>& nodes);
|
|
58
|
+
void clear_node_cache(JSContext* ctx, RuntimeContext* rctx);
|
|
59
|
+
|
|
60
|
+
// ── Accessor property helper ──────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
using GetterFn = JSValue (*)(JSContext*, JSValue);
|
|
63
|
+
using SetterFn = JSValue (*)(JSContext*, JSValue, JSValue);
|
|
64
|
+
|
|
65
|
+
void define_prop(JSContext* ctx, JSValue obj, const char* name, GetterFn getter, SetterFn setter = nullptr);
|
|
66
|
+
|
|
67
|
+
// ── Misc shared helpers ───────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
// Reads a boolean-ish property off any JS object (used by Event dispatch to read
|
|
70
|
+
// bubbles/cancelable/defaultPrevented/internal propagation flags).
|
|
71
|
+
bool get_bool_prop(JSContext* ctx, JSValue obj, const char* name);
|
|
72
|
+
|
|
73
|
+
// Builds a CSS selector matching elements with every class in `names` (a
|
|
74
|
+
// space-separated list), e.g. "foo bar" -> ".foo.bar". Shared by
|
|
75
|
+
// Element::getElementsByClassName and document.getElementsByClassName.
|
|
76
|
+
std::string classNames_to_selector(const std::string& names);
|
|
77
|
+
|
|
78
|
+
// camelCase <-> kebab-case conversion shared by DatasetBindings (data-foo-bar
|
|
79
|
+
// <-> fooBar) and StyleBindings (background-color <-> backgroundColor).
|
|
80
|
+
std::string attr_suffix_to_camel(const std::string& suffix);
|
|
81
|
+
std::string camel_to_attr_suffix(const std::string& camel);
|
|
82
|
+
|
|
83
|
+
} // namespace margelo::nitro::nitrojsdom
|