Prototype resolution of Zig types previously had 2 limitations (bug?). The first
was that the Zig prototype chain could only be 1 deep. You couldn't do A->B->C
where each of those was a Zig type (but you could do A->B->C->D->E ... so long
as every other type was a C opaque value).
The other limitation was that Zig prototypes only worked when the nested field
was directly embedded in the struct (i.e. not a pointer). So you could do:
```zig
const X = struct {
proto: XParent,
};
```
But not:
```zig
const X = struct {
proto: *XParent,
};
```
This addresses both limitations. The first issue is solved by keeping track
of the cumulative offset
Only when setAttribute is called directly on the element, does libdom raise
a `DOMAttrModified` event (which MutationObserver uses).
From what I can tell, libdom's element set attribute _does_ rely on the
underlying attribute set value, so the behavior should be pretty close, it just
does extra things on top of that.
Previously, MutationObserver callbacks where called using the `jsCallScopeEnd`
mechanism. This was slow and resulted in records split in a way that callers
might not expect. `jsCallScopeEnd` has been removed.
The new approach uses the loop.timeout mechanism, much like a window.setTimeout
and only registers a timeout when events have been handled. It should perform
much better.
Exactly how MutationRecords are supposed to be grouped is still a mystery to me.
This new grouping is still wrong in many cases (according to WPT), but appears
slightly less wrong; I'm pretty hopeful clients don't really have hard-coded
expectations for this though.
Also implement the attributeFilter option of MutationObserver. (Github)
document.createElement('a').host or .href or .. should return an empty string.
However, URL.constructor(document.createElement('a')) should fail.
Because HTMLAnchorElement uses URL.constructor, we have the wrong behavior.
This adds a guard for an empty anchor. This might not cover all of the cases
which are valid for an anchor but invalid for a URL.constructor, but it's
the most common.
I think we initially thought we might need different clients for different
parts of the system, each with a unique loop (e.g. we thought telemetry might
need some isolation). But that never happened, so it's just needless now,
especially since the async connect uses the non-generic *Loop type directly.
Deal with non-node current target crashing. Builds ontop of abort_signal, but
with the new event-target specific union, I think this will work in for all
future cases.
Don't error on JSON.stringify failure (likely caused by circular reference).
In debug mode, try to print [slightly] more meaningful value representation
when default serialization results in [object Object].