solid-tag-runtime 0.0.7 → 0.0.8
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/ARCHITECTURE.md +113 -0
- package/README.md +118 -15
- package/html.d.ts +49 -0
- package/index.d.ts +42 -1
- package/package.json +1 -1
- package/src/events.js +63 -0
- package/src/html.js +299 -24
- package/src/runtime.js +198 -94
package/src/html.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SolidTagRuntimeError } from "./errors.js";
|
|
2
|
+
import { createEventDispatcher } from "./events.js";
|
|
2
3
|
|
|
3
4
|
const DEFAULT_SELECTOR = [
|
|
4
5
|
'script[type="solid-jsx"]',
|
|
@@ -47,6 +48,11 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
47
48
|
const controller = {
|
|
48
49
|
id: `solid-tag-html-${++controllerSequence}`,
|
|
49
50
|
runtime,
|
|
51
|
+
events: createEventDispatcher({
|
|
52
|
+
onListenerError(error) {
|
|
53
|
+
globalThis.console?.error?.("solid-tag-runtime/html lifecycle subscriber error", error);
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
50
56
|
scope: normalizeScope(options.scope),
|
|
51
57
|
root: options.root,
|
|
52
58
|
selector: options.selector ?? DEFAULT_SELECTOR,
|
|
@@ -88,6 +94,7 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
88
94
|
get appendTarget() {
|
|
89
95
|
return getAppendTarget(controller);
|
|
90
96
|
},
|
|
97
|
+
subscribe,
|
|
91
98
|
register,
|
|
92
99
|
observe,
|
|
93
100
|
flush,
|
|
@@ -109,20 +116,41 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
109
116
|
controller.api = api;
|
|
110
117
|
return api;
|
|
111
118
|
|
|
119
|
+
function subscribe(typesOrListener, maybeListener) {
|
|
120
|
+
return controller.events.subscribe(typesOrListener, maybeListener);
|
|
121
|
+
}
|
|
122
|
+
|
|
112
123
|
/** One-shot scan of matching scripts. */
|
|
113
124
|
async function register(callOptions = {}) {
|
|
114
125
|
const root = getRoot(mergeOptions(controller, callOptions), "HTML runtime register");
|
|
115
126
|
const selector = callOptions.selector ?? controller.selector;
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
127
|
+
const origin = callOptions.origin ?? "initial-scan";
|
|
128
|
+
const discovered = Array.from(root.querySelectorAll(selector));
|
|
129
|
+
const elements = [];
|
|
130
|
+
|
|
131
|
+
for (const element of discovered) {
|
|
132
|
+
const accepted = acceptsDiscoveredElement(controller, element, callOptions);
|
|
133
|
+
emitHTML(controller, {
|
|
134
|
+
type: "element-discovered",
|
|
135
|
+
element,
|
|
136
|
+
moduleId: nonEmpty(element?.getAttribute?.("module")),
|
|
137
|
+
origin,
|
|
138
|
+
accepted,
|
|
139
|
+
});
|
|
140
|
+
if (accepted) elements.push(element);
|
|
141
|
+
}
|
|
119
142
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
try {
|
|
144
|
+
return await processElements(controller, elements, {
|
|
145
|
+
...callOptions,
|
|
146
|
+
root,
|
|
147
|
+
origin,
|
|
148
|
+
executeEntries: callOptions.executeEntries ?? controller.executeEntries,
|
|
149
|
+
});
|
|
150
|
+
} catch (error) {
|
|
151
|
+
emitHTMLError(controller, "register", error, { origin });
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
126
154
|
}
|
|
127
155
|
|
|
128
156
|
/**
|
|
@@ -174,6 +202,15 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
174
202
|
*/
|
|
175
203
|
async function setRoot(root, callOptions = {}) {
|
|
176
204
|
const nextRoot = getRoot({ root }, "HTML runtime setRoot");
|
|
205
|
+
const previousRoot = controller.root ?? globalThis.document;
|
|
206
|
+
const previousAppendTarget = getAppendTarget(controller);
|
|
207
|
+
emitHTML(controller, {
|
|
208
|
+
type: "root-changing",
|
|
209
|
+
previousRoot,
|
|
210
|
+
root: nextRoot,
|
|
211
|
+
connected: controller.connected,
|
|
212
|
+
registerExisting: callOptions.registerExisting ?? controller.connected,
|
|
213
|
+
});
|
|
177
214
|
|
|
178
215
|
// Finish work scheduled against the old root before rebinding observer state.
|
|
179
216
|
await controller.queue;
|
|
@@ -186,7 +223,7 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
186
223
|
const wasConnected = controller.connected;
|
|
187
224
|
const previousObserverOptions = controller.observerOptions ?? {};
|
|
188
225
|
|
|
189
|
-
if (wasConnected) stopObserver(controller, { preserveOptions: true });
|
|
226
|
+
if (wasConnected) stopObserver(controller, { preserveOptions: true, reason: "root-change" });
|
|
190
227
|
|
|
191
228
|
controller.root = nextRoot;
|
|
192
229
|
if (Object.prototype.hasOwnProperty.call(callOptions, "appendTo")) {
|
|
@@ -204,10 +241,13 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
204
241
|
};
|
|
205
242
|
controller.observerOptions = { ...observeOptions };
|
|
206
243
|
try {
|
|
207
|
-
|
|
244
|
+
const result = await connectObserver(controller, nextRoot, observeOptions, {
|
|
208
245
|
registerExisting,
|
|
209
246
|
initial: false,
|
|
247
|
+
reason: "root-change",
|
|
210
248
|
});
|
|
249
|
+
emitRootChanged(controller, previousRoot, nextRoot, registerExisting, previousAppendTarget);
|
|
250
|
+
return result;
|
|
211
251
|
} catch (error) {
|
|
212
252
|
stopObserver(controller, { preserveOptions: true });
|
|
213
253
|
throw error;
|
|
@@ -215,9 +255,12 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
215
255
|
}
|
|
216
256
|
|
|
217
257
|
if (registerExisting) {
|
|
218
|
-
|
|
258
|
+
const result = await register({ ...callOptions, root: nextRoot, origin: callOptions.origin ?? "root-change-scan" });
|
|
259
|
+
emitRootChanged(controller, previousRoot, nextRoot, registerExisting, previousAppendTarget);
|
|
260
|
+
return result;
|
|
219
261
|
}
|
|
220
262
|
|
|
263
|
+
emitRootChanged(controller, previousRoot, nextRoot, registerExisting, previousAppendTarget);
|
|
221
264
|
return emptyRegistrationResult();
|
|
222
265
|
}
|
|
223
266
|
|
|
@@ -235,7 +278,15 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
235
278
|
if (!target || (typeof target.append !== "function" && typeof target.appendChild !== "function")) {
|
|
236
279
|
throw new TypeError("setAppendTarget() requires a target with append() or appendChild().");
|
|
237
280
|
}
|
|
281
|
+
const previousTarget = getAppendTarget(controller);
|
|
238
282
|
controller.appendTo = target;
|
|
283
|
+
if (previousTarget !== target) {
|
|
284
|
+
emitHTML(controller, {
|
|
285
|
+
type: "append-target-changed",
|
|
286
|
+
previousTarget,
|
|
287
|
+
target,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
239
290
|
return api;
|
|
240
291
|
}
|
|
241
292
|
|
|
@@ -268,6 +319,12 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
268
319
|
*/
|
|
269
320
|
async function updateElement(element, callOptions = {}) {
|
|
270
321
|
const record = requireOwnedRecord(controller, element, "updateElement");
|
|
322
|
+
emitHTML(controller, {
|
|
323
|
+
type: "element-updating",
|
|
324
|
+
element,
|
|
325
|
+
moduleId: record.moduleId,
|
|
326
|
+
origin: callOptions.origin ?? "update-element",
|
|
327
|
+
});
|
|
271
328
|
const metadata = inspectElement(controller, element, {
|
|
272
329
|
...callOptions,
|
|
273
330
|
existingId: record.moduleId,
|
|
@@ -302,16 +359,41 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
302
359
|
|
|
303
360
|
if (record.entry && (callOptions.executeEntries ?? controller.executeEntries) !== false) {
|
|
304
361
|
record.state = "executing";
|
|
362
|
+
emitHTML(controller, {
|
|
363
|
+
type: "entry-executing",
|
|
364
|
+
element,
|
|
365
|
+
moduleId: record.moduleId,
|
|
366
|
+
origin: callOptions.origin ?? "update-element",
|
|
367
|
+
});
|
|
305
368
|
try {
|
|
306
|
-
await runtime.import(record.moduleId);
|
|
369
|
+
const namespace = await runtime.import(record.moduleId);
|
|
307
370
|
record.state = "ready";
|
|
371
|
+
emitHTML(controller, {
|
|
372
|
+
type: "entry-executed",
|
|
373
|
+
element,
|
|
374
|
+
moduleId: record.moduleId,
|
|
375
|
+
namespace,
|
|
376
|
+
origin: callOptions.origin ?? "update-element",
|
|
377
|
+
});
|
|
308
378
|
} catch (error) {
|
|
309
379
|
record.state = "error";
|
|
310
380
|
record.error = error;
|
|
381
|
+
emitHTMLError(controller, "entry", error, {
|
|
382
|
+
element,
|
|
383
|
+
moduleId: record.moduleId,
|
|
384
|
+
origin: callOptions.origin ?? "update-element",
|
|
385
|
+
});
|
|
311
386
|
throw error;
|
|
312
387
|
}
|
|
313
388
|
}
|
|
314
389
|
|
|
390
|
+
emitHTML(controller, {
|
|
391
|
+
type: "element-updated",
|
|
392
|
+
element,
|
|
393
|
+
moduleId: record.moduleId,
|
|
394
|
+
definition: record.definition,
|
|
395
|
+
origin: callOptions.origin ?? "update-element",
|
|
396
|
+
});
|
|
315
397
|
return record.definition;
|
|
316
398
|
}
|
|
317
399
|
|
|
@@ -322,6 +404,15 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
322
404
|
*/
|
|
323
405
|
async function removeElement(element, callOptions = {}) {
|
|
324
406
|
const record = requireOwnedRecord(controller, element, "removeElement");
|
|
407
|
+
const origin = callOptions.origin ?? "remove-element";
|
|
408
|
+
emitHTML(controller, {
|
|
409
|
+
type: "element-removing",
|
|
410
|
+
element,
|
|
411
|
+
moduleId: record.moduleId,
|
|
412
|
+
origin,
|
|
413
|
+
removeModule: callOptions.removeModule !== false,
|
|
414
|
+
removeFromDOM: callOptions.removeFromDOM !== false,
|
|
415
|
+
});
|
|
325
416
|
const removeModule = callOptions.removeModule !== false;
|
|
326
417
|
const removeFromDOM = callOptions.removeFromDOM !== false;
|
|
327
418
|
const invalidateDependents = callOptions.invalidateDependents !== false;
|
|
@@ -334,6 +425,12 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
334
425
|
controller.bindings.delete(record.moduleId);
|
|
335
426
|
elementOwners.delete(element);
|
|
336
427
|
record.state = "removed";
|
|
428
|
+
emitHTML(controller, {
|
|
429
|
+
type: "element-released",
|
|
430
|
+
element,
|
|
431
|
+
moduleId: record.moduleId,
|
|
432
|
+
origin,
|
|
433
|
+
});
|
|
337
434
|
|
|
338
435
|
let elementRemoved = false;
|
|
339
436
|
if (removeFromDOM) {
|
|
@@ -344,12 +441,21 @@ export function createHTMLRuntime(runtime, options = {}) {
|
|
|
344
441
|
controller.ignoredExisting.add(element);
|
|
345
442
|
}
|
|
346
443
|
|
|
347
|
-
|
|
444
|
+
const result = {
|
|
348
445
|
id: record.moduleId,
|
|
349
446
|
element,
|
|
350
447
|
moduleRemoved,
|
|
351
448
|
elementRemoved,
|
|
352
449
|
};
|
|
450
|
+
emitHTML(controller, {
|
|
451
|
+
type: "element-removed",
|
|
452
|
+
element,
|
|
453
|
+
moduleId: record.moduleId,
|
|
454
|
+
origin,
|
|
455
|
+
moduleRemoved,
|
|
456
|
+
elementRemoved,
|
|
457
|
+
});
|
|
458
|
+
return result;
|
|
353
459
|
}
|
|
354
460
|
|
|
355
461
|
/**
|
|
@@ -497,6 +603,13 @@ async function connectObserver(controller, root, callOptions = {}, mode = {}) {
|
|
|
497
603
|
childList: true,
|
|
498
604
|
subtree: callOptions.subtree ?? controller.subtree,
|
|
499
605
|
});
|
|
606
|
+
emitHTML(controller, {
|
|
607
|
+
type: "observer-connected",
|
|
608
|
+
root,
|
|
609
|
+
subtree: callOptions.subtree ?? controller.subtree,
|
|
610
|
+
registerExisting,
|
|
611
|
+
reason: mode.reason ?? (mode.initial ? "observe" : "connect"),
|
|
612
|
+
});
|
|
500
613
|
|
|
501
614
|
const result = registerExisting
|
|
502
615
|
? await enqueueObserverScan(controller, {
|
|
@@ -511,11 +624,17 @@ async function connectObserver(controller, root, callOptions = {}, mode = {}) {
|
|
|
511
624
|
|
|
512
625
|
function stopObserver(controller, options = {}) {
|
|
513
626
|
if (!controller.connected && !controller.observer) return;
|
|
627
|
+
const root = controller.observerRoot;
|
|
514
628
|
controller.connected = false;
|
|
515
629
|
controller.observer?.disconnect();
|
|
516
630
|
controller.observer = undefined;
|
|
517
631
|
controller.observerRoot = undefined;
|
|
518
632
|
if (!options.preserveOptions) controller.observerOptions = undefined;
|
|
633
|
+
emitHTML(controller, {
|
|
634
|
+
type: "observer-disconnected",
|
|
635
|
+
root,
|
|
636
|
+
reason: options.reason ?? "disconnect",
|
|
637
|
+
});
|
|
519
638
|
}
|
|
520
639
|
|
|
521
640
|
async function enqueueObserverScan(controller, callOptions = {}) {
|
|
@@ -524,23 +643,76 @@ async function enqueueObserverScan(controller, callOptions = {}) {
|
|
|
524
643
|
|
|
525
644
|
const root = controller.observerRoot ?? getRoot(mergeOptions(controller, callOptions), "HTML runtime observer");
|
|
526
645
|
const selector = callOptions.selector ?? controller.selector;
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
646
|
+
const origin = callOptions.origin ?? "observer";
|
|
647
|
+
const discovered = Array.from(root.querySelectorAll(selector));
|
|
648
|
+
const elements = [];
|
|
649
|
+
let matched = 0;
|
|
650
|
+
let ignored = 0;
|
|
651
|
+
|
|
652
|
+
for (const element of discovered) {
|
|
653
|
+
if (controller.ignoredExisting.has(element)) {
|
|
654
|
+
ignored += 1;
|
|
655
|
+
emitHTML(controller, {
|
|
656
|
+
type: "element-discovered",
|
|
657
|
+
element,
|
|
658
|
+
moduleId: nonEmpty(element?.getAttribute?.("module")),
|
|
659
|
+
origin,
|
|
660
|
+
accepted: false,
|
|
661
|
+
});
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const accepted = acceptsDiscoveredElement(controller, element, callOptions);
|
|
666
|
+
emitHTML(controller, {
|
|
667
|
+
type: "element-discovered",
|
|
668
|
+
element,
|
|
669
|
+
moduleId: nonEmpty(element?.getAttribute?.("module")),
|
|
670
|
+
origin,
|
|
671
|
+
accepted,
|
|
672
|
+
});
|
|
673
|
+
if (!accepted) {
|
|
674
|
+
ignored += 1;
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
matched += 1;
|
|
530
678
|
|
|
531
679
|
const ownership = elementOwners.get(element);
|
|
532
|
-
if (!ownership)
|
|
533
|
-
|
|
680
|
+
if (!ownership) {
|
|
681
|
+
elements.push(element);
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
if (ownership.owner === controller) {
|
|
685
|
+
ignored += 1;
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
534
688
|
|
|
535
689
|
throw ownershipError(controller, element, ownership);
|
|
536
|
-
}
|
|
690
|
+
}
|
|
537
691
|
|
|
538
|
-
|
|
539
|
-
|
|
692
|
+
let result;
|
|
693
|
+
try {
|
|
694
|
+
result = await processElements(controller, elements, {
|
|
695
|
+
...callOptions,
|
|
696
|
+
root,
|
|
697
|
+
origin,
|
|
698
|
+
executeEntries: callOptions.executeEntries ?? controller.executeEntries,
|
|
699
|
+
});
|
|
700
|
+
} catch (error) {
|
|
701
|
+
emitHTMLError(controller, "observer", error, { origin });
|
|
702
|
+
throw error;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
emitHTML(controller, {
|
|
706
|
+
type: "observer-batch",
|
|
540
707
|
root,
|
|
541
|
-
origin
|
|
542
|
-
|
|
708
|
+
origin,
|
|
709
|
+
discovered: discovered.length,
|
|
710
|
+
matched,
|
|
711
|
+
claimed: result.modules.length,
|
|
712
|
+
ignored,
|
|
713
|
+
modules: result.modules.map(module => module.id),
|
|
543
714
|
});
|
|
715
|
+
return result;
|
|
544
716
|
});
|
|
545
717
|
|
|
546
718
|
controller.queue = task.then(
|
|
@@ -587,6 +759,12 @@ async function processClaims(controller, records, options = {}) {
|
|
|
587
759
|
try {
|
|
588
760
|
prepared = await Promise.all(records.map(record => prepareRecordSource(controller, record, options)));
|
|
589
761
|
} catch (error) {
|
|
762
|
+
const failed = records.find(record => record.state === "loading") ?? records[0];
|
|
763
|
+
emitHTMLError(controller, failed?.sourceUrl ? "fetch" : "register", error, {
|
|
764
|
+
element: failed?.element,
|
|
765
|
+
moduleId: failed?.moduleId,
|
|
766
|
+
origin: failed?.origin ?? options.origin,
|
|
767
|
+
});
|
|
590
768
|
for (const record of records) rejectRecord(record, error);
|
|
591
769
|
throw error;
|
|
592
770
|
}
|
|
@@ -604,8 +782,21 @@ async function processClaims(controller, records, options = {}) {
|
|
|
604
782
|
record.definition = definitionFromRecord(record);
|
|
605
783
|
record.resolve(record.definition);
|
|
606
784
|
modules.push(record.definition);
|
|
785
|
+
emitHTML(controller, {
|
|
786
|
+
type: "element-registered",
|
|
787
|
+
element: record.element,
|
|
788
|
+
moduleId: record.moduleId,
|
|
789
|
+
definition: record.definition,
|
|
790
|
+
origin: record.origin,
|
|
791
|
+
});
|
|
607
792
|
}
|
|
608
793
|
} catch (error) {
|
|
794
|
+
const failed = records.find(record => record.state === "claimed" || record.state === "loading") ?? records[0];
|
|
795
|
+
emitHTMLError(controller, "register", error, {
|
|
796
|
+
element: failed?.element,
|
|
797
|
+
moduleId: failed?.moduleId,
|
|
798
|
+
origin: failed?.origin ?? options.origin,
|
|
799
|
+
});
|
|
609
800
|
for (const record of records) {
|
|
610
801
|
if (record.state === "claimed" || record.state === "loading") rejectRecord(record, error);
|
|
611
802
|
}
|
|
@@ -621,14 +812,32 @@ async function processClaims(controller, records, options = {}) {
|
|
|
621
812
|
if (record) record.state = "executing";
|
|
622
813
|
|
|
623
814
|
try {
|
|
815
|
+
emitHTML(controller, {
|
|
816
|
+
type: "entry-executing",
|
|
817
|
+
element: entry.element,
|
|
818
|
+
moduleId: entry.id,
|
|
819
|
+
origin: record?.origin ?? options.origin ?? "entry",
|
|
820
|
+
});
|
|
624
821
|
const namespace = await controller.runtime.import(entry.id);
|
|
625
822
|
if (record) record.state = "ready";
|
|
626
823
|
executed.push({ id: entry.id, namespace });
|
|
824
|
+
emitHTML(controller, {
|
|
825
|
+
type: "entry-executed",
|
|
826
|
+
element: entry.element,
|
|
827
|
+
moduleId: entry.id,
|
|
828
|
+
namespace,
|
|
829
|
+
origin: record?.origin ?? options.origin ?? "entry",
|
|
830
|
+
});
|
|
627
831
|
} catch (error) {
|
|
628
832
|
if (record) {
|
|
629
833
|
record.state = "error";
|
|
630
834
|
record.error = error;
|
|
631
835
|
}
|
|
836
|
+
emitHTMLError(controller, "entry", error, {
|
|
837
|
+
element: entry.element,
|
|
838
|
+
moduleId: entry.id,
|
|
839
|
+
origin: record?.origin ?? options.origin ?? "entry",
|
|
840
|
+
});
|
|
632
841
|
throw error;
|
|
633
842
|
}
|
|
634
843
|
}
|
|
@@ -701,6 +910,15 @@ function claimElement(controller, element, options = {}) {
|
|
|
701
910
|
|
|
702
911
|
elementOwners.set(element, record);
|
|
703
912
|
controller.bindings.set(moduleId, record);
|
|
913
|
+
emitHTML(controller, {
|
|
914
|
+
type: "element-claimed",
|
|
915
|
+
element,
|
|
916
|
+
moduleId,
|
|
917
|
+
format: record.format,
|
|
918
|
+
entry: record.entry,
|
|
919
|
+
sourceUrl: record.sourceUrl,
|
|
920
|
+
origin: record.origin,
|
|
921
|
+
});
|
|
704
922
|
return { fresh: true, record };
|
|
705
923
|
}
|
|
706
924
|
|
|
@@ -709,12 +927,29 @@ async function prepareRecordSource(controller, record, options) {
|
|
|
709
927
|
|
|
710
928
|
let source;
|
|
711
929
|
if (record.sourceUrl) {
|
|
930
|
+
const startedAt = performanceNow();
|
|
931
|
+
emitHTML(controller, {
|
|
932
|
+
type: "element-loading",
|
|
933
|
+
element: record.element,
|
|
934
|
+
moduleId: record.moduleId,
|
|
935
|
+
sourceUrl: record.sourceUrl,
|
|
936
|
+
origin: record.origin,
|
|
937
|
+
});
|
|
712
938
|
source = await fetchSource(
|
|
713
939
|
record.sourceUrl,
|
|
714
940
|
options.fetch ?? controller.fetch ?? globalThis.fetch,
|
|
715
941
|
record.element,
|
|
716
942
|
record.moduleId,
|
|
717
943
|
);
|
|
944
|
+
emitHTML(controller, {
|
|
945
|
+
type: "element-loaded",
|
|
946
|
+
element: record.element,
|
|
947
|
+
moduleId: record.moduleId,
|
|
948
|
+
sourceUrl: record.sourceUrl,
|
|
949
|
+
origin: record.origin,
|
|
950
|
+
bytes: String(source).length,
|
|
951
|
+
durationMs: performanceNow() - startedAt,
|
|
952
|
+
});
|
|
718
953
|
} else {
|
|
719
954
|
source = record.element.textContent ?? "";
|
|
720
955
|
}
|
|
@@ -863,6 +1098,46 @@ function ownershipError(controller, element, ownership) {
|
|
|
863
1098
|
);
|
|
864
1099
|
}
|
|
865
1100
|
|
|
1101
|
+
function emitHTML(controller, event) {
|
|
1102
|
+
controller.events.emit({
|
|
1103
|
+
htmlRuntimeId: controller.id,
|
|
1104
|
+
scope: controller.scope,
|
|
1105
|
+
timestamp: Date.now(),
|
|
1106
|
+
...event,
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
function emitHTMLError(controller, operation, error, context = {}) {
|
|
1111
|
+
emitHTML(controller, {
|
|
1112
|
+
type: "html-error",
|
|
1113
|
+
operation,
|
|
1114
|
+
error,
|
|
1115
|
+
...context,
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function emitRootChanged(controller, previousRoot, root, registerExisting, previousAppendTarget) {
|
|
1120
|
+
emitHTML(controller, {
|
|
1121
|
+
type: "root-changed",
|
|
1122
|
+
previousRoot,
|
|
1123
|
+
root,
|
|
1124
|
+
registerExisting,
|
|
1125
|
+
connected: controller.connected,
|
|
1126
|
+
});
|
|
1127
|
+
const nextAppendTarget = getAppendTarget(controller);
|
|
1128
|
+
if (previousAppendTarget !== nextAppendTarget) {
|
|
1129
|
+
emitHTML(controller, {
|
|
1130
|
+
type: "append-target-changed",
|
|
1131
|
+
previousTarget: previousAppendTarget,
|
|
1132
|
+
target: nextAppendTarget,
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
function performanceNow() {
|
|
1138
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1139
|
+
}
|
|
1140
|
+
|
|
866
1141
|
function getDefaultController(runtime, options = {}) {
|
|
867
1142
|
assertRuntime(runtime);
|
|
868
1143
|
let controller = defaultControllers.get(runtime);
|