@salve-software/react-native-nitro-jsdom 1.1.0 → 2.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/android/CMakeLists.txt +6 -0
- package/cpp/HybridHtmlSandbox.cpp +14 -7
- package/cpp/HybridHtmlSandbox.hpp +1 -1
- package/cpp/lexbor/LexborDocument.cpp +65 -3
- package/cpp/lexbor/LexborDocument.hpp +17 -2
- package/cpp/quickjs/DOMBindings.cpp +14 -1
- package/cpp/quickjs/DOMBindingsInternal.cpp +67 -0
- package/cpp/quickjs/DOMBindingsInternal.hpp +39 -0
- package/cpp/quickjs/QuickJSRuntime.cpp +13 -0
- package/cpp/quickjs/QuickJSRuntime.hpp +29 -0
- package/cpp/quickjs/bindings/AbortBindings.cpp +14 -0
- package/cpp/quickjs/bindings/BlobBindings.cpp +28 -1
- package/cpp/quickjs/bindings/BlobBindings.hpp +3 -3
- package/cpp/quickjs/bindings/CSSOMBindings.cpp +96 -0
- package/cpp/quickjs/bindings/CSSOMBindings.hpp +3 -1
- package/cpp/quickjs/bindings/CustomElementsBindings.cpp +1 -1
- package/cpp/quickjs/bindings/DOMParserBindings.cpp +299 -0
- package/cpp/quickjs/bindings/DOMParserBindings.hpp +45 -0
- package/cpp/quickjs/bindings/DocumentBindings.cpp +174 -11
- package/cpp/quickjs/bindings/ElementBindings.cpp +516 -20
- package/cpp/quickjs/bindings/EventBindings.cpp +281 -5
- package/cpp/quickjs/bindings/EventBindings.hpp +3 -0
- package/cpp/quickjs/bindings/EventTargetBindings.cpp +75 -0
- package/cpp/quickjs/bindings/EventTargetBindings.hpp +24 -0
- package/cpp/quickjs/bindings/FetchBindings.cpp +43 -8
- package/cpp/quickjs/bindings/FormBindings.cpp +294 -0
- package/cpp/quickjs/bindings/FormBindings.hpp +9 -5
- package/cpp/quickjs/bindings/IntlBindings.cpp +352 -0
- package/cpp/quickjs/bindings/IntlBindings.hpp +29 -0
- package/cpp/quickjs/bindings/LayoutStubBindings.cpp +104 -0
- package/cpp/quickjs/bindings/LayoutStubBindings.hpp +28 -0
- package/cpp/quickjs/bindings/LiveCollectionBindings.cpp +45 -0
- package/cpp/quickjs/bindings/TimerBindings.cpp +79 -0
- package/cpp/quickjs/bindings/TreeWalkerBindings.cpp +306 -0
- package/cpp/quickjs/bindings/TreeWalkerBindings.hpp +28 -0
- package/cpp/quickjs/bindings/UrlBindings.cpp +43 -0
- package/cpp/quickjs/bindings/WindowBindings.cpp +295 -4
- package/cpp/quickjs/bindings/WindowBindings.hpp +3 -2
- package/cpp/quickjs/bindings/WindowNamedPropertiesBindings.cpp +241 -0
- package/cpp/quickjs/bindings/WindowNamedPropertiesBindings.hpp +30 -0
- package/lib/commonjs/classes/JSDOM/JSDOM.class.js +2 -1
- package/lib/commonjs/classes/JSDOM/JSDOM.class.js.map +1 -1
- package/lib/module/classes/JSDOM/JSDOM.class.js +2 -1
- package/lib/module/classes/JSDOM/JSDOM.class.js.map +1 -1
- package/lib/typescript/src/classes/JSDOM/JSDOM.class.d.ts.map +1 -1
- package/lib/typescript/src/classes/JSDOM/types/IJSDOMOptions.d.ts +5 -4
- package/lib/typescript/src/classes/JSDOM/types/IJSDOMOptions.d.ts.map +1 -1
- package/lib/typescript/src/specs/HtmlSandbox.nitro.d.ts +1 -1
- package/lib/typescript/src/specs/HtmlSandbox.nitro.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/HybridHtmlSandboxSpec.hpp +1 -1
- package/package.json +17 -2
- package/src/classes/JSDOM/JSDOM.class.ts +2 -1
- package/src/classes/JSDOM/types/IJSDOMOptions.ts +5 -4
- package/src/specs/HtmlSandbox.nitro.ts +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#include "WindowBindings.hpp"
|
|
2
2
|
#include "DOMExceptionBindings.hpp"
|
|
3
|
+
#include "EventBindings.hpp"
|
|
3
4
|
#include "../DOMBindingsInternal.hpp"
|
|
4
5
|
#include "../QuickJSRuntime.hpp"
|
|
6
|
+
#include <cstdlib>
|
|
5
7
|
#include <cstring>
|
|
6
8
|
#include <optional>
|
|
7
|
-
#include <random>
|
|
8
9
|
#include <string>
|
|
9
10
|
#include <vector>
|
|
10
11
|
|
|
@@ -191,6 +192,23 @@ JSValue js_console_method(JSContext* ctx, JSValue, int argc, JSValue* argv, int
|
|
|
191
192
|
return JS_UNDEFINED;
|
|
192
193
|
}
|
|
193
194
|
|
|
195
|
+
JSValue js_window_reportError(JSContext* ctx, JSValue, int argc, JSValue* argv) {
|
|
196
|
+
JSValue error_value = argc >= 1 ? argv[0] : JS_UNDEFINED;
|
|
197
|
+
std::string message = "Uncaught";
|
|
198
|
+
if (argc >= 1) {
|
|
199
|
+
JSValue msg_prop = JS_GetPropertyStr(ctx, argv[0], "message");
|
|
200
|
+
if (!JS_IsException(msg_prop) && !JS_IsUndefined(msg_prop)) {
|
|
201
|
+
const char* s = JS_ToCString(ctx, msg_prop);
|
|
202
|
+
if (s) { message = s; JS_FreeCString(ctx, s); }
|
|
203
|
+
} else if (JS_IsException(msg_prop)) {
|
|
204
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
205
|
+
}
|
|
206
|
+
JS_FreeValue(ctx, msg_prop);
|
|
207
|
+
}
|
|
208
|
+
EventBindings::dispatchErrorEvent(ctx, message, error_value);
|
|
209
|
+
return JS_UNDEFINED;
|
|
210
|
+
}
|
|
211
|
+
|
|
194
212
|
// ── window.alert / confirm / prompt ───────────────────────────────────────────
|
|
195
213
|
|
|
196
214
|
JSValue js_window_alert(JSContext* ctx, JSValue, int argc, JSValue* argv) {
|
|
@@ -336,6 +354,15 @@ const char* kLocationBootstrapScript = R"JS(
|
|
|
336
354
|
globalThis.Location = Location;
|
|
337
355
|
globalThis.location = new Location(globalThis.__initialHref);
|
|
338
356
|
delete globalThis.__initialHref;
|
|
357
|
+
|
|
358
|
+
if (typeof document !== 'undefined') {
|
|
359
|
+
Object.defineProperty(document, 'location', {
|
|
360
|
+
get: function() { return location; },
|
|
361
|
+
set: function(v) { location.href = v; },
|
|
362
|
+
enumerable: true,
|
|
363
|
+
configurable: true,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
339
366
|
})();
|
|
340
367
|
)JS";
|
|
341
368
|
|
|
@@ -346,12 +373,12 @@ JSValue js_native_random_bytes(JSContext* ctx, JSValue, int argc, JSValue* argv)
|
|
|
346
373
|
if (argc >= 1) JS_ToInt32(ctx, &count, argv[0]);
|
|
347
374
|
if (count < 0) count = 0;
|
|
348
375
|
|
|
349
|
-
|
|
350
|
-
|
|
376
|
+
std::vector<uint8_t> bytes(static_cast<size_t>(count));
|
|
377
|
+
if (count > 0) arc4random_buf(bytes.data(), bytes.size());
|
|
351
378
|
|
|
352
379
|
JSValue arr = JS_NewArray(ctx);
|
|
353
380
|
for (int32_t i = 0; i < count; i++) {
|
|
354
|
-
JS_SetPropertyUint32(ctx, arr, static_cast<uint32_t>(i), JS_NewInt32(ctx,
|
|
381
|
+
JS_SetPropertyUint32(ctx, arr, static_cast<uint32_t>(i), JS_NewInt32(ctx, bytes[static_cast<size_t>(i)]));
|
|
355
382
|
}
|
|
356
383
|
return arr;
|
|
357
384
|
}
|
|
@@ -373,6 +400,67 @@ const char* kCryptoBootstrapScript = R"JS(
|
|
|
373
400
|
for (var i = 0; i < bytes.length; i++) view[i] = bytes[i];
|
|
374
401
|
return typedArray;
|
|
375
402
|
};
|
|
403
|
+
globalThis.crypto.randomUUID = function() {
|
|
404
|
+
var bytes = __nativeRandomBytes(16);
|
|
405
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
406
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
407
|
+
var hex = [];
|
|
408
|
+
for (var i = 0; i < 16; i++) {
|
|
409
|
+
var h = bytes[i].toString(16);
|
|
410
|
+
hex.push(h.length === 1 ? '0' + h : h);
|
|
411
|
+
}
|
|
412
|
+
return hex.slice(0, 4).join('') + '-' + hex.slice(4, 6).join('') + '-' +
|
|
413
|
+
hex.slice(6, 8).join('') + '-' + hex.slice(8, 10).join('') + '-' + hex.slice(10, 16).join('');
|
|
414
|
+
};
|
|
415
|
+
})();
|
|
416
|
+
)JS";
|
|
417
|
+
|
|
418
|
+
// ── console ergonomics (group/table/assert/trace/count) ──────────────────────
|
|
419
|
+
// Layered in pure JS on top of the native log/warn/error/info/debug methods
|
|
420
|
+
// above rather than adding new native levels — none of these need anything
|
|
421
|
+
// the onConsole callback can't already receive as stringified args.
|
|
422
|
+
|
|
423
|
+
const char* kConsoleExtrasBootstrapScript = R"JS(
|
|
424
|
+
(function() {
|
|
425
|
+
var counts = Object.create(null);
|
|
426
|
+
|
|
427
|
+
console.group = function() {
|
|
428
|
+
console.log.apply(console, arguments);
|
|
429
|
+
};
|
|
430
|
+
console.groupCollapsed = console.group;
|
|
431
|
+
console.groupEnd = function() {};
|
|
432
|
+
|
|
433
|
+
console.trace = function() {
|
|
434
|
+
var args = Array.prototype.slice.call(arguments);
|
|
435
|
+
args.unshift('Trace:');
|
|
436
|
+
console.log.apply(console, args);
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
console.assert = function(condition) {
|
|
440
|
+
if (condition) return;
|
|
441
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
442
|
+
args.unshift('Assertion failed:');
|
|
443
|
+
console.error.apply(console, args);
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
console.table = function(data) {
|
|
447
|
+
try {
|
|
448
|
+
console.log(JSON.stringify(data));
|
|
449
|
+
} catch (e) {
|
|
450
|
+
console.log(String(data));
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
console.count = function(label) {
|
|
455
|
+
label = label === undefined ? 'default' : String(label);
|
|
456
|
+
counts[label] = (counts[label] || 0) + 1;
|
|
457
|
+
console.log(label + ': ' + counts[label]);
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
console.countReset = function(label) {
|
|
461
|
+
label = label === undefined ? 'default' : String(label);
|
|
462
|
+
counts[label] = 0;
|
|
463
|
+
};
|
|
376
464
|
})();
|
|
377
465
|
)JS";
|
|
378
466
|
|
|
@@ -389,10 +477,184 @@ const char* kNavigatorBootstrapScript = R"JS(
|
|
|
389
477
|
cookieEnabled: false,
|
|
390
478
|
hardwareConcurrency: 1,
|
|
391
479
|
};
|
|
480
|
+
navigator.sendBeacon = function(url, data) {
|
|
481
|
+
try {
|
|
482
|
+
fetch(url, { method: 'POST', body: data }).catch(function() {});
|
|
483
|
+
} catch (e) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
return true;
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// jsdom itself doesn't implement the Clipboard API at all (no OS clipboard
|
|
490
|
+
// to back it, same reasoning as window.history/getSelection). This is an
|
|
491
|
+
// in-memory stand-in purely so 'copy discount code'-style embedded widgets
|
|
492
|
+
// that call navigator.clipboard.writeText() directly don't throw — reads
|
|
493
|
+
// back whatever was last written, nothing more.
|
|
494
|
+
var clipboardText = '';
|
|
495
|
+
navigator.clipboard = {
|
|
496
|
+
writeText: function(text) {
|
|
497
|
+
clipboardText = String(text);
|
|
498
|
+
return Promise.resolve();
|
|
499
|
+
},
|
|
500
|
+
readText: function() {
|
|
501
|
+
return Promise.resolve(clipboardText);
|
|
502
|
+
},
|
|
503
|
+
};
|
|
504
|
+
|
|
392
505
|
globalThis.navigator = navigator;
|
|
393
506
|
})();
|
|
394
507
|
)JS";
|
|
395
508
|
|
|
509
|
+
// ── structuredClone ────────────────────────────────────────────────────────
|
|
510
|
+
|
|
511
|
+
const char* kStructuredCloneBootstrapScript = R"JS(
|
|
512
|
+
(function() {
|
|
513
|
+
globalThis.structuredClone = function(value) {
|
|
514
|
+
var seen = new Map();
|
|
515
|
+
function clone(v) {
|
|
516
|
+
if (v === null || typeof v !== 'object') {
|
|
517
|
+
if (typeof v === 'function' || typeof v === 'symbol') {
|
|
518
|
+
throw new DOMException(String(v) + ' could not be cloned.', 'DataCloneError');
|
|
519
|
+
}
|
|
520
|
+
return v;
|
|
521
|
+
}
|
|
522
|
+
if (seen.has(v)) return seen.get(v);
|
|
523
|
+
if (v instanceof Date) return new Date(v.getTime());
|
|
524
|
+
if (v instanceof RegExp) return new RegExp(v.source, v.flags);
|
|
525
|
+
if (Array.isArray(v)) {
|
|
526
|
+
var arr = [];
|
|
527
|
+
seen.set(v, arr);
|
|
528
|
+
for (var i = 0; i < v.length; i++) arr.push(clone(v[i]));
|
|
529
|
+
return arr;
|
|
530
|
+
}
|
|
531
|
+
if (v instanceof Map) {
|
|
532
|
+
var m = new Map();
|
|
533
|
+
seen.set(v, m);
|
|
534
|
+
v.forEach(function(val, key) { m.set(clone(key), clone(val)); });
|
|
535
|
+
return m;
|
|
536
|
+
}
|
|
537
|
+
if (v instanceof Set) {
|
|
538
|
+
var s = new Set();
|
|
539
|
+
seen.set(v, s);
|
|
540
|
+
v.forEach(function(val) { s.add(clone(val)); });
|
|
541
|
+
return s;
|
|
542
|
+
}
|
|
543
|
+
if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView && ArrayBuffer.isView(v)) {
|
|
544
|
+
return new v.constructor(v);
|
|
545
|
+
}
|
|
546
|
+
if (typeof ArrayBuffer !== 'undefined' && v instanceof ArrayBuffer) {
|
|
547
|
+
return v.slice(0);
|
|
548
|
+
}
|
|
549
|
+
var proto = Object.getPrototypeOf(v);
|
|
550
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
551
|
+
throw new DOMException('The object could not be cloned.', 'DataCloneError');
|
|
552
|
+
}
|
|
553
|
+
var out = {};
|
|
554
|
+
seen.set(v, out);
|
|
555
|
+
for (var key in v) {
|
|
556
|
+
if (Object.prototype.hasOwnProperty.call(v, key)) out[key] = clone(v[key]);
|
|
557
|
+
}
|
|
558
|
+
return out;
|
|
559
|
+
}
|
|
560
|
+
return clone(value);
|
|
561
|
+
};
|
|
562
|
+
})();
|
|
563
|
+
)JS";
|
|
564
|
+
|
|
565
|
+
// ── window.history ────────────────────────────────────────────────────────
|
|
566
|
+
// No real page navigation exists in this sandbox, so History tracks its own
|
|
567
|
+
// in-memory entry stack rather than session history. pushState/replaceState
|
|
568
|
+
// never fire popstate (per spec); go/back/forward do, since those are the
|
|
569
|
+
// events CMS-widget routers actually listen for. `title` is accepted but
|
|
570
|
+
// ignored (same as jsdom — nothing renders a document title). State is
|
|
571
|
+
// structuredClone()'d on write (per spec — matches pushState/replaceState's
|
|
572
|
+
// documented "serializable" semantics), so callers mutating their object
|
|
573
|
+
// after the call can't leak into a stored entry. `go()`'s delta is truncated
|
|
574
|
+
// to an integer so a fractional/NaN input can't produce a non-integer
|
|
575
|
+
// `_index`.
|
|
576
|
+
|
|
577
|
+
const char* kHistoryBootstrapScript = R"JS(
|
|
578
|
+
(function() {
|
|
579
|
+
function History() {
|
|
580
|
+
this._entries = [null];
|
|
581
|
+
this._index = 0;
|
|
582
|
+
}
|
|
583
|
+
Object.defineProperty(History.prototype, 'length', {
|
|
584
|
+
get: function() { return this._entries.length; },
|
|
585
|
+
enumerable: true,
|
|
586
|
+
});
|
|
587
|
+
Object.defineProperty(History.prototype, 'state', {
|
|
588
|
+
get: function() { return this._entries[this._index]; },
|
|
589
|
+
enumerable: true,
|
|
590
|
+
});
|
|
591
|
+
function cloneState(state) {
|
|
592
|
+
return state === undefined ? null : structuredClone(state);
|
|
593
|
+
}
|
|
594
|
+
History.prototype.pushState = function(state, _title, url) {
|
|
595
|
+
this._entries = this._entries.slice(0, this._index + 1);
|
|
596
|
+
this._entries.push(cloneState(state));
|
|
597
|
+
this._index++;
|
|
598
|
+
if (url !== undefined && url !== null) location.href = url;
|
|
599
|
+
};
|
|
600
|
+
History.prototype.replaceState = function(state, _title, url) {
|
|
601
|
+
this._entries[this._index] = cloneState(state);
|
|
602
|
+
if (url !== undefined && url !== null) location.href = url;
|
|
603
|
+
};
|
|
604
|
+
History.prototype.go = function(delta) {
|
|
605
|
+
delta = delta === undefined ? 0 : Math.trunc(Number(delta) || 0);
|
|
606
|
+
if (delta === 0) return;
|
|
607
|
+
var next = this._index + delta;
|
|
608
|
+
if (next < 0 || next > this._entries.length - 1) return;
|
|
609
|
+
this._index = next;
|
|
610
|
+
var ev = new Event('popstate');
|
|
611
|
+
ev.state = this._entries[this._index];
|
|
612
|
+
dispatchEvent(ev);
|
|
613
|
+
};
|
|
614
|
+
History.prototype.back = function() { this.go(-1); };
|
|
615
|
+
History.prototype.forward = function() { this.go(1); };
|
|
616
|
+
|
|
617
|
+
globalThis.History = History;
|
|
618
|
+
globalThis.history = new History();
|
|
619
|
+
})();
|
|
620
|
+
)JS";
|
|
621
|
+
|
|
622
|
+
// ── window.getSelection ──────────────────────────────────────────────────
|
|
623
|
+
// No layout engine backs this sandbox, so there is nothing to select — this
|
|
624
|
+
// mirrors matchMedia's stance: an always-empty Selection rather than a
|
|
625
|
+
// missing global, so defensive `window.getSelection().toString()` checks in
|
|
626
|
+
// third-party scripts don't crash the sandbox.
|
|
627
|
+
|
|
628
|
+
const char* kSelectionBootstrapScript = R"JS(
|
|
629
|
+
(function() {
|
|
630
|
+
function Selection() {}
|
|
631
|
+
Object.defineProperty(Selection.prototype, 'rangeCount', { get: function() { return 0; }, enumerable: true });
|
|
632
|
+
Object.defineProperty(Selection.prototype, 'isCollapsed', { get: function() { return true; }, enumerable: true });
|
|
633
|
+
Object.defineProperty(Selection.prototype, 'anchorNode', { get: function() { return null; }, enumerable: true });
|
|
634
|
+
Object.defineProperty(Selection.prototype, 'anchorOffset', { get: function() { return 0; }, enumerable: true });
|
|
635
|
+
Object.defineProperty(Selection.prototype, 'focusNode', { get: function() { return null; }, enumerable: true });
|
|
636
|
+
Object.defineProperty(Selection.prototype, 'focusOffset', { get: function() { return 0; }, enumerable: true });
|
|
637
|
+
Object.defineProperty(Selection.prototype, 'type', { get: function() { return 'None'; }, enumerable: true });
|
|
638
|
+
Selection.prototype.toString = function() { return ''; };
|
|
639
|
+
Selection.prototype.removeAllRanges = function() {};
|
|
640
|
+
Selection.prototype.collapse = function() {};
|
|
641
|
+
Selection.prototype.collapseToStart = function() {};
|
|
642
|
+
Selection.prototype.collapseToEnd = function() {};
|
|
643
|
+
Selection.prototype.selectAllChildren = function() {};
|
|
644
|
+
Selection.prototype.addRange = function() {};
|
|
645
|
+
Selection.prototype.containsNode = function() { return false; };
|
|
646
|
+
Selection.prototype.getRangeAt = function(index) {
|
|
647
|
+
throw new DOMException(
|
|
648
|
+
"Failed to execute 'getRangeAt' on 'Selection': " + index + ' is not a valid index.', 'IndexSizeError');
|
|
649
|
+
};
|
|
650
|
+
Selection.prototype.empty = Selection.prototype.removeAllRanges;
|
|
651
|
+
|
|
652
|
+
var selectionInstance = new Selection();
|
|
653
|
+
globalThis.Selection = Selection;
|
|
654
|
+
globalThis.getSelection = function() { return selectionInstance; };
|
|
655
|
+
})();
|
|
656
|
+
)JS";
|
|
657
|
+
|
|
396
658
|
// ── matchMedia ─────────────────────────────────────────────────────────────
|
|
397
659
|
// No layout engine backs this sandbox, so every query reports "no match" —
|
|
398
660
|
// mirrors jsdom's own stance that layout-dependent APIs return inert defaults
|
|
@@ -435,6 +697,7 @@ void WindowBindings::install(JSContext* ctx) {
|
|
|
435
697
|
JS_SetPropertyStr(ctx, global, "alert", JS_NewCFunction(ctx, js_window_alert, "alert", 1));
|
|
436
698
|
JS_SetPropertyStr(ctx, global, "confirm", JS_NewCFunction(ctx, js_window_confirm, "confirm", 1));
|
|
437
699
|
JS_SetPropertyStr(ctx, global, "prompt", JS_NewCFunction(ctx, js_window_prompt, "prompt", 2));
|
|
700
|
+
JS_SetPropertyStr(ctx, global, "reportError", JS_NewCFunction(ctx, js_window_reportError, "reportError", 1));
|
|
438
701
|
JS_SetPropertyStr(ctx, global, "atob", JS_NewCFunction(ctx, js_window_atob, "atob", 1));
|
|
439
702
|
JS_SetPropertyStr(ctx, global, "btoa", JS_NewCFunction(ctx, js_window_btoa, "btoa", 1));
|
|
440
703
|
|
|
@@ -456,6 +719,27 @@ void WindowBindings::install(JSContext* ctx) {
|
|
|
456
719
|
}
|
|
457
720
|
JS_FreeValue(ctx, location_result);
|
|
458
721
|
|
|
722
|
+
JSValue history_result = JS_Eval(ctx, kHistoryBootstrapScript, strlen(kHistoryBootstrapScript),
|
|
723
|
+
"<history-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
724
|
+
if (JS_IsException(history_result)) {
|
|
725
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
726
|
+
}
|
|
727
|
+
JS_FreeValue(ctx, history_result);
|
|
728
|
+
|
|
729
|
+
JSValue selection_result = JS_Eval(ctx, kSelectionBootstrapScript, strlen(kSelectionBootstrapScript),
|
|
730
|
+
"<selection-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
731
|
+
if (JS_IsException(selection_result)) {
|
|
732
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
733
|
+
}
|
|
734
|
+
JS_FreeValue(ctx, selection_result);
|
|
735
|
+
|
|
736
|
+
JSValue console_extras_result = JS_Eval(ctx, kConsoleExtrasBootstrapScript, strlen(kConsoleExtrasBootstrapScript),
|
|
737
|
+
"<console-extras-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
738
|
+
if (JS_IsException(console_extras_result)) {
|
|
739
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
740
|
+
}
|
|
741
|
+
JS_FreeValue(ctx, console_extras_result);
|
|
742
|
+
|
|
459
743
|
JSValue crypto_result = JS_Eval(ctx, kCryptoBootstrapScript, strlen(kCryptoBootstrapScript),
|
|
460
744
|
"<crypto-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
461
745
|
if (JS_IsException(crypto_result)) {
|
|
@@ -476,6 +760,13 @@ void WindowBindings::install(JSContext* ctx) {
|
|
|
476
760
|
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
477
761
|
}
|
|
478
762
|
JS_FreeValue(ctx, match_media_result);
|
|
763
|
+
|
|
764
|
+
JSValue structured_clone_result = JS_Eval(ctx, kStructuredCloneBootstrapScript, strlen(kStructuredCloneBootstrapScript),
|
|
765
|
+
"<structured-clone-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
766
|
+
if (JS_IsException(structured_clone_result)) {
|
|
767
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
768
|
+
}
|
|
769
|
+
JS_FreeValue(ctx, structured_clone_result);
|
|
479
770
|
}
|
|
480
771
|
|
|
481
772
|
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
// window.alert/confirm/prompt (bridged to onAlert/onConfirm/onPrompt native
|
|
4
|
-
// callbacks), console.log/warn/error/info/debug, and the window.location
|
|
5
|
-
//
|
|
4
|
+
// callbacks), console.log/warn/error/info/debug, and the window.location,
|
|
5
|
+
// window.history, window.getSelection, crypto, navigator, matchMedia, and
|
|
6
|
+
// structuredClone bootstrap scripts.
|
|
6
7
|
|
|
7
8
|
#include "quickjs.h"
|
|
8
9
|
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#include "WindowNamedPropertiesBindings.hpp"
|
|
2
|
+
#include <cstring>
|
|
3
|
+
|
|
4
|
+
namespace margelo::nitro::nitrojsdom {
|
|
5
|
+
|
|
6
|
+
namespace {
|
|
7
|
+
|
|
8
|
+
const char* kWindowNamedPropertiesBootstrapScript = R"JS(
|
|
9
|
+
(function() {
|
|
10
|
+
var NAME_ATTR_TAGS = { embed: 1, form: 1, img: 1, object: 1, iframe: 1, frame: 1 };
|
|
11
|
+
|
|
12
|
+
// registry: key -> element[] currently claiming it. owned: key -> true once
|
|
13
|
+
// this module has written globalThis[key] (so it knows it's safe to delete
|
|
14
|
+
// or reassign later without clobbering something else's global).
|
|
15
|
+
var registry = Object.create(null);
|
|
16
|
+
var owned = Object.create(null);
|
|
17
|
+
|
|
18
|
+
function isConnected(el) {
|
|
19
|
+
var docEl = document.documentElement;
|
|
20
|
+
var n = el;
|
|
21
|
+
while (n) {
|
|
22
|
+
if (n === docEl) return true;
|
|
23
|
+
n = n.parentNode;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function refreshKey(key) {
|
|
29
|
+
var els = registry[key];
|
|
30
|
+
if (!els || els.length === 0) {
|
|
31
|
+
if (owned[key]) { delete globalThis[key]; delete owned[key]; }
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!owned[key] && (key in globalThis)) return; // don't clobber a real global
|
|
35
|
+
globalThis[key] = els.length === 1 ? els[0] : els.slice();
|
|
36
|
+
owned[key] = true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function addToRegistry(key, el) {
|
|
40
|
+
if (!key) return;
|
|
41
|
+
var els = registry[key] || (registry[key] = []);
|
|
42
|
+
if (els.indexOf(el) === -1) els.push(el);
|
|
43
|
+
refreshKey(key);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function removeFromRegistry(key, el) {
|
|
47
|
+
if (!key) return;
|
|
48
|
+
var els = registry[key];
|
|
49
|
+
if (!els) return;
|
|
50
|
+
var idx = els.indexOf(el);
|
|
51
|
+
if (idx !== -1) els.splice(idx, 1);
|
|
52
|
+
refreshKey(key);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function keysFor(el) {
|
|
56
|
+
var keys = [];
|
|
57
|
+
var id = el.getAttribute ? el.getAttribute('id') : null;
|
|
58
|
+
if (id) keys.push(id);
|
|
59
|
+
var tag = el.tagName ? el.tagName.toLowerCase() : '';
|
|
60
|
+
if (NAME_ATTR_TAGS[tag]) {
|
|
61
|
+
var name = el.getAttribute('name');
|
|
62
|
+
if (name) keys.push(name);
|
|
63
|
+
}
|
|
64
|
+
return keys;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function registerIfConnected(el) {
|
|
68
|
+
if (!el || el.nodeType !== 1 || !isConnected(el)) return;
|
|
69
|
+
keysFor(el).forEach(function(k) { addToRegistry(k, el); });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function unregister(el) {
|
|
73
|
+
if (!el || el.nodeType !== 1) return;
|
|
74
|
+
keysFor(el).forEach(function(k) { removeFromRegistry(k, el); });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function registerSubtree(root) {
|
|
78
|
+
if (!root) return;
|
|
79
|
+
if (root.nodeType === 1) registerIfConnected(root);
|
|
80
|
+
if (typeof root.querySelectorAll !== 'function') return;
|
|
81
|
+
var found = root.querySelectorAll('*');
|
|
82
|
+
for (var i = 0; i < found.length; i++) registerIfConnected(found[i]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function unregisterSubtree(root) {
|
|
86
|
+
if (!root) return;
|
|
87
|
+
if (root.nodeType === 1) unregister(root);
|
|
88
|
+
if (typeof root.querySelectorAll !== 'function') return;
|
|
89
|
+
var found = root.querySelectorAll('*');
|
|
90
|
+
for (var i = 0; i < found.length; i++) unregister(found[i]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function collectSubtreeKeys(root) {
|
|
94
|
+
var pending = [];
|
|
95
|
+
function collect(el) {
|
|
96
|
+
if (!el || el.nodeType !== 1) return;
|
|
97
|
+
keysFor(el).forEach(function(k) { pending.push({ key: k, el: el }); });
|
|
98
|
+
}
|
|
99
|
+
if (!root) return pending;
|
|
100
|
+
collect(root);
|
|
101
|
+
if (typeof root.querySelectorAll === 'function') {
|
|
102
|
+
var found = root.querySelectorAll('*');
|
|
103
|
+
for (var i = 0; i < found.length; i++) collect(found[i]);
|
|
104
|
+
}
|
|
105
|
+
return pending;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function commitUnregister(pending) {
|
|
109
|
+
pending.forEach(function(entry) { removeFromRegistry(entry.key, entry.el); });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── Initial population: elements already present in the parsed document ──
|
|
113
|
+
if (document.documentElement) registerSubtree(document.documentElement);
|
|
114
|
+
|
|
115
|
+
// ── appendChild / removeChild ─────────────────────────────────────────
|
|
116
|
+
var DOCUMENT_FRAGMENT_NODE = 11;
|
|
117
|
+
|
|
118
|
+
var origAppendChild = Node.prototype.appendChild;
|
|
119
|
+
Node.prototype.appendChild = function(child) {
|
|
120
|
+
var moved = (child && child.nodeType === DOCUMENT_FRAGMENT_NODE)
|
|
121
|
+
? Array.prototype.slice.call(child.childNodes)
|
|
122
|
+
: [child];
|
|
123
|
+
var result = origAppendChild.call(this, child);
|
|
124
|
+
moved.forEach(registerSubtree);
|
|
125
|
+
return result;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
var origRemoveChild = Node.prototype.removeChild;
|
|
129
|
+
Node.prototype.removeChild = function(child) {
|
|
130
|
+
var pending = collectSubtreeKeys(child);
|
|
131
|
+
var willRemove = child && child.parentNode === this;
|
|
132
|
+
var result = origRemoveChild.call(this, child);
|
|
133
|
+
if (willRemove) commitUnregister(pending);
|
|
134
|
+
return result;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
var origRemove = Element.prototype.remove;
|
|
138
|
+
Element.prototype.remove = function() {
|
|
139
|
+
var pending = collectSubtreeKeys(this);
|
|
140
|
+
var hadParent = this.parentNode !== null;
|
|
141
|
+
var result = origRemove.call(this);
|
|
142
|
+
if (hadParent) commitUnregister(pending);
|
|
143
|
+
return result;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// ── innerHTML ────────────────────────────────────────────────────────
|
|
147
|
+
var innerHTMLDesc = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
|
|
148
|
+
if (innerHTMLDesc && innerHTMLDesc.set) {
|
|
149
|
+
var origInnerHTMLSet = innerHTMLDesc.set;
|
|
150
|
+
Object.defineProperty(Element.prototype, 'innerHTML', {
|
|
151
|
+
get: innerHTMLDesc.get,
|
|
152
|
+
set: function(html) {
|
|
153
|
+
unregisterSubtree(this); // walk the OLD content before it's replaced
|
|
154
|
+
origInnerHTMLSet.call(this, html);
|
|
155
|
+
registerSubtree(this); // register the NEW content
|
|
156
|
+
},
|
|
157
|
+
enumerable: innerHTMLDesc.enumerable,
|
|
158
|
+
configurable: true,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var textContentDesc = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent');
|
|
163
|
+
if (textContentDesc && textContentDesc.set) {
|
|
164
|
+
var origTextContentSet = textContentDesc.set;
|
|
165
|
+
Object.defineProperty(Node.prototype, 'textContent', {
|
|
166
|
+
get: textContentDesc.get,
|
|
167
|
+
set: function(value) {
|
|
168
|
+
unregisterSubtree(this);
|
|
169
|
+
origTextContentSet.call(this, value);
|
|
170
|
+
},
|
|
171
|
+
enumerable: textContentDesc.enumerable,
|
|
172
|
+
configurable: true,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ── insertAdjacentHTML ──────────────────────────────────────────────
|
|
177
|
+
var origInsertAdjacentHTML = Element.prototype.insertAdjacentHTML;
|
|
178
|
+
Element.prototype.insertAdjacentHTML = function(position, html) {
|
|
179
|
+
origInsertAdjacentHTML.call(this, position, html);
|
|
180
|
+
var pos = String(position).toLowerCase();
|
|
181
|
+
registerSubtree((pos === 'beforebegin' || pos === 'afterend') ? (this.parentNode || this) : this);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// ── element.id (native accessor property — bypasses setAttribute) ──
|
|
185
|
+
var idDesc = Object.getOwnPropertyDescriptor(Element.prototype, 'id');
|
|
186
|
+
if (idDesc && idDesc.set) {
|
|
187
|
+
var origIdSet = idDesc.set;
|
|
188
|
+
Object.defineProperty(Element.prototype, 'id', {
|
|
189
|
+
get: idDesc.get,
|
|
190
|
+
set: function(value) {
|
|
191
|
+
var oldValue = this.getAttribute('id');
|
|
192
|
+
origIdSet.call(this, value);
|
|
193
|
+
if (oldValue) removeFromRegistry(oldValue, this);
|
|
194
|
+
registerIfConnected(this);
|
|
195
|
+
},
|
|
196
|
+
enumerable: idDesc.enumerable,
|
|
197
|
+
configurable: true,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ── setAttribute / removeAttribute (id/name changes) ───────────────
|
|
202
|
+
function isTrackedAttr(el, name) {
|
|
203
|
+
var lower = String(name).toLowerCase();
|
|
204
|
+
if (lower === 'id') return true;
|
|
205
|
+
var tag = el.tagName ? el.tagName.toLowerCase() : '';
|
|
206
|
+
return lower === 'name' && !!NAME_ATTR_TAGS[tag];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
var origSetAttribute = Element.prototype.setAttribute;
|
|
210
|
+
Element.prototype.setAttribute = function(name, value) {
|
|
211
|
+
var tracked = isTrackedAttr(this, name);
|
|
212
|
+
var oldValue = tracked ? this.getAttribute(name) : null;
|
|
213
|
+
origSetAttribute.call(this, name, value);
|
|
214
|
+
if (tracked) {
|
|
215
|
+
if (oldValue) removeFromRegistry(oldValue, this);
|
|
216
|
+
registerIfConnected(this);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
var origRemoveAttribute = Element.prototype.removeAttribute;
|
|
221
|
+
Element.prototype.removeAttribute = function(name) {
|
|
222
|
+
var tracked = isTrackedAttr(this, name);
|
|
223
|
+
var oldValue = tracked ? this.getAttribute(name) : null;
|
|
224
|
+
origRemoveAttribute.call(this, name);
|
|
225
|
+
if (tracked && oldValue) removeFromRegistry(oldValue, this);
|
|
226
|
+
};
|
|
227
|
+
})();
|
|
228
|
+
)JS";
|
|
229
|
+
|
|
230
|
+
} // namespace
|
|
231
|
+
|
|
232
|
+
void WindowNamedPropertiesBindings::install(JSContext* ctx) {
|
|
233
|
+
JSValue result = JS_Eval(ctx, kWindowNamedPropertiesBootstrapScript, strlen(kWindowNamedPropertiesBootstrapScript),
|
|
234
|
+
"<window-named-properties-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
235
|
+
if (JS_IsException(result)) {
|
|
236
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
237
|
+
}
|
|
238
|
+
JS_FreeValue(ctx, result);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "quickjs.h"
|
|
4
|
+
|
|
5
|
+
namespace margelo::nitro::nitrojsdom {
|
|
6
|
+
|
|
7
|
+
// Implements "named access on the Window object"
|
|
8
|
+
// (https://html.spec.whatwg.org/#named-access-on-the-window-object): an
|
|
9
|
+
// element with an `id`, or a `name` attribute on `embed`/`form`/`img`/
|
|
10
|
+
// `object`/`iframe`/`frame`, becomes reachable as a bare global while
|
|
11
|
+
// connected to the primary document.
|
|
12
|
+
//
|
|
13
|
+
// Pure JS, monkey-patching appendChild/removeChild/remove/innerHTML/
|
|
14
|
+
// textContent/insertAdjacentHTML/setAttribute/removeAttribute/the `id`
|
|
15
|
+
// accessor — no new native bindings, no engine-level Proxy (QuickJS's real
|
|
16
|
+
// global object can't be swapped for one), so exposure is push-based.
|
|
17
|
+
//
|
|
18
|
+
// Duplicate ids/names resolve to a plain array, not a live `HTMLCollection`
|
|
19
|
+
// (same trade-off as `form.elements`/`element.labels`). insertBefore/before/
|
|
20
|
+
// after/replaceWith/append/prepend/insertAdjacentElement are not hooked
|
|
21
|
+
// (same scope CustomElementsBindings' connectivity tracking accepted).
|
|
22
|
+
// Never overwrites a key already present on `globalThis`.
|
|
23
|
+
//
|
|
24
|
+
// Must run last in DOMBindings::install (after localStorage/sessionStorage
|
|
25
|
+
// exist, so it never claims those keys).
|
|
26
|
+
struct WindowNamedPropertiesBindings {
|
|
27
|
+
static void install(JSContext* ctx);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -47,7 +47,8 @@ class JSDOM {
|
|
|
47
47
|
sandbox.setConsoleCallback(null);
|
|
48
48
|
}
|
|
49
49
|
if (options?.onAlert || options?.onConfirm || options?.onPrompt) {
|
|
50
|
-
|
|
50
|
+
const onConfirm = options.onConfirm;
|
|
51
|
+
sandbox.setDialogCallbacks(options.onAlert ?? null, onConfirm ? async message => await onConfirm(message) : null, options.onPrompt ?? null);
|
|
51
52
|
}
|
|
52
53
|
if (options?.onFetch) {
|
|
53
54
|
const onFetch = options.onFetch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNativeNitroModules","require","safeParseHeaders","headersJson","parsed","JSON","parse","JSDOM","_disposed","constructor","sandbox","create","html","options","NitroModules","createHybridObject","initialize","runScripts","url","pretendToBeVisual","onConsole","cb","setConsoleCallback","level","args","onAlert","onConfirm","onPrompt","setDialogCallbacks","onFetch","setFetchCallback","method","body","headers","then","res","stringify","ok","status","statusText","catch","err","error","Error","
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","safeParseHeaders","headersJson","parsed","JSON","parse","JSDOM","_disposed","constructor","sandbox","create","html","options","NitroModules","createHybridObject","initialize","runScripts","url","pretendToBeVisual","onConsole","cb","setConsoleCallback","level","args","onAlert","onConfirm","onPrompt","setDialogCallbacks","message","onFetch","setFetchCallback","method","body","headers","then","res","stringify","ok","status","statusText","catch","err","error","Error","String","evaluate","script","Promise","reject","serialize","dispose","exports"],"sourceRoot":"../../../../src","sources":["classes/JSDOM/JSDOM.class.ts"],"mappings":"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","ignoreList":[]}
|