Commit Graph

8321 Commits

Author SHA1 Message Date
Rohit
d75ef37d42 feat(cdp): implement Accessibility.getPartialAXTree
The Accessibility domain handled getFullAXTree and queryAXTree but not
getPartialAXTree, so a client asking for the accessibility subtree rooted at
a specific node got UnknownMethod. Tools like Playwright/Puppeteer and
axe-core use getPartialAXTree for scoped a11y snapshots.

Add it by mirroring the existing methods: resolve the node via dom.getNode
(like queryAXTree) and emit its unfiltered AX subtree via bc.axnodeWriter
(like getFullAXTree). fetchRelatives is accepted for protocol compatibility;
subtree emission matches queryAXTree's scope. Adds tests for the missing-id
and unknown-id error paths.
2026-07-15 16:36:20 +05:30
Adrià Arrufat
98134feb7a prompt_assist: use explicit PathMatchIterator.init 2026-07-15 12:34:35 +02:00
Adrià Arrufat
1d8a0b9fc4 agent: trim narrative comments from the terminal split 2026-07-15 12:20:56 +02:00
Karl Seguin
9d138c1780 Merge pull request #2952 from lightpanda-io/dom-pr-11-mutation-records
webapi: insert-adjacent semantics; combined mutation records
2026-07-15 18:18:37 +08:00
Adrià Arrufat
f462223277 agent: tighten the seams the terminal split left behind
- attachCompleter now takes the CompletionSource: Agent no longer
  reaches through terminal.assist to configure what it just attached,
  and attach/configure can't be sequenced wrong.
- history_paths flows through one channel: attach() loads the initial
  history from the same State field modeCallback swaps from, instead of
  setupRepl receiving a second copy that had to agree.
- all_names + closestCommand move to SlashCommand.zig, the command
  registry - prompt_assist consumes it like everyone else and
  Terminal's closestCommand re-export disappears.
- picker treats a tty that refuses raw mode as NotInteractive and
  degrades to the line prompt instead of leaking termios errnos to
  callers that can only blanket-catch.
- kitty keyboard flags become named ansi.zig constants shared by
  Terminal.readLine and picker's RawTerminal.
- skipWhitespace was std.mem.indexOfNonePos; single-use style consts
  inline into the style table; drop the dead CompletionSource default
  and doc-comment splice in Spinner.
2026-07-15 12:16:53 +02:00
Adrià Arrufat
6845c3a542 agent: use decl-literal init syntax in picker and prompt_assist 2026-07-15 12:05:34 +02:00
Adrià Arrufat
b4c971799c agent: share one filesystem scan between path completion and ghost hint
addPathCompletions and ghostPathFirstMatch were ~20-line twins (split
dir/base, openDir, iterate, prefix-match, '/' suffix for directories).
A fix landing in one copy — hidden-file filtering, the shared
symlink-to-directory suffix gap — would make Tab completion and the
ghost hint disagree. Both now consume one PathMatchIterator.
2026-07-15 11:56:27 +02:00
Adrià Arrufat
2d43d5103e agent: derive prompt style registration and kind mapping from one table
ic_style_def registration lived in setup while the Kind->style switch
lived 600 lines away in IcSink: adding a js_highlight.Kind
compile-errored the sink but silently skipped registration, rendering
the new kind unstyled with no test able to catch it (isocline is
live-only). One table now drives both; an unmapped or doubly-mapped
kind is a compile error.
2026-07-15 11:53:56 +02:00
Francis Bouvier
ecf7dd2137 webapi: use the local arena for Table.collectRows
Review pattern from #2943: prefer the local arena for scratch-only
allocations. The collected row list is only read before deleteRow's
removeChild call - the one point that can re-enter JS - so it does not
need to survive a nested callback.

Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
2026-07-15 17:53:10 +08:00
Francis Bouvier
20299e4b5c webapi: node length and Range text offsets are UTF-16 code units
Fixes the remaining failures of WPT /dom/ranges/Range-selectNode.html
(288/292) and improves several other /dom/ranges files: for
CharacterData, the DOM "node length" is the data length in UTF-16 code
units, but Node.getLength returned the UTF-8 byte length, so
selectNodeContents() on text containing non-ASCII set endOffset to the
byte count (25 instead of 17 in the test's fixture).

Node.getLength now defers to CData.getLength (already UTF-16). Since
Range/Selection offsets are therefore UTF-16 units, the Range routines
that slice the UTF-8 data by offset (insertNode's text split,
deleteContents, cloneContents, toString) convert them with
utf16OffsetToUtf8 (clamped to the end) instead of using them as byte
indices, which would cut surrogate pairs and multi-byte sequences
apart.

Coverage:
- /dom/ranges/Range-selectNode.html 288/292 -> 292/292 (fully green)
- /dom/ranges/Range-deleteContents.html 95/125 -> 105/125
- /dom/ranges/Range-extractContents.html 128/187 -> 141/187
- /dom/ranges/Range-cloneContents.html 168/187 -> 171/187

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 17:53:10 +08:00
Francis Bouvier
f197fd6388 webapi: Text.wholeText spans contiguous Text siblings
Fixes WPT /dom/nodes/Text-wholeText.html: wholeText must return the
concatenated data of the contiguous exclusive Text nodes (adjacent Text
siblings on both sides of the node) in tree order; we returned only the
node's own data.

The old own-data behavior is what every internal caller (semantic tree,
markdown dump, AX names, textarea default value, textContent) actually
wants, since they iterate the text nodes themselves; those now use the
new Text.ownData helper, and getWholeText implements the spec walk
(single-node case stays allocation-free).

Coverage: /dom/nodes/Text-wholeText.html 0/1 -> 1/1 (fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 17:53:10 +08:00
Francis Bouvier
8b1baec769 webapi: class tokens split on all ASCII whitespace; table row collections
Fixes 7 failing WPT /dom/nodes/getElementsByClassName-*.htm files:

- Class attribute matching (getElementsByClassName and .class
  selectors) treated only the space character as a token separator, so
  class="a\nb" or class="a\tb" never matched "a". Per the spec the
  separators are ASCII whitespace (tab, LF, FF, CR, space);
  classAttributeContains now accepts all of them at token boundaries
  (deliberately not std.ascii.isWhitespace, which would also accept
  vertical tab). Fixes getElementsByClassName-02/04/15/22/25.

- getElementsByClassName-20 exercised table.tBodies[0].rows[0].cells[0]
  and -21 table.deleteRow(1); the table interfaces were bare stubs.
  Added HTMLTableElement.tBodies (child tbody collection),
  HTMLTableSectionElement.rows (child tr collection),
  HTMLTableRowElement.cells (child td/th collection, a new `cells`
  NodeLive mode since child_tag filters a single tag), and
  HTMLTableElement.deleteRow with the spec's row ordering (thead rows,
  then table/tbody rows in tree order, then tfoot rows), -1 meaning the
  last row, and IndexSizeError for out-of-range indices.

Coverage: getElementsByClassName-02/04/15/20/21/22/25.htm each
0/1 -> 1/1 (fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 17:53:10 +08:00
Karl Seguin
7945df66ba more local_arena, less pub 2026-07-15 17:52:24 +08:00
Adrià Arrufat
673b16528f agent: extract prompt assistance into prompt_assist.zig
Completion, ghost hints, and prompt highlighting (~640 lines) were
cohabiting with Terminal's readline lifecycle and output printing. They
now live in prompt_assist.zig, which owns the isocline callbacks, the
ps-* style palette, and the slash-command name table. The C callbacks
read a small prompt_assist.State (js_mode, completion_source,
history_paths) embedded in Terminal, replacing the three loose fields.
Pure code motion otherwise; the valueAt/renderSchemaHint tests move
with their code and stay in the suite via Terminal's test hook.
2026-07-15 11:50:44 +02:00
Pierre Tachoire
0562e774f0 Merge pull request #2966 from lightpanda-io/blob-lifetime
uaf: Dupe blobs before using them, or else risk revokeObjectURL
2026-07-15 11:49:43 +02:00
Adrià Arrufat
f48498073d agent: extract the choice picker into picker.zig
The numbered/interactive picker (ChoiceState, RawTerminal, render loop)
was ~215 self-contained lines inside Terminal.zig. It runs before - or
without - the isocline REPL (provider selection during setup), so
settings.zig no longer imports the isocline-configured Terminal at all.
Pure code motion; the ChoiceState tests move with it and stay in the
suite via Agent.zig's test hook.
2026-07-15 11:40:55 +02:00
Adrià Arrufat
772a3fc7db agent: move terminal width query into its only user, Spinner
Terminal.columns() had exactly one caller (Spinner's line renderer) and
Terminal itself never used it. Moving it breaks the Spinner<->Terminal
import cycle and stops Spinner type-checking against the isocline
@cImport for one ioctl.
2026-07-15 11:36:31 +02:00
Karl Seguin
fbe229c4bd uaf: Dupe blobs before using them, or else risk revokeObjectURL
When using a blob that might live through a JS call, dupe it so that any
subsequent revokeObjectURL doesn't invalidate the memory.
2026-07-15 17:24:35 +08:00
Adrià Arrufat
44193a6fca Merge pull request #2932 from lightpanda-io/agent-repl-markdown-output
agent: render markdown in REPL output
2026-07-15 11:18:52 +02:00
Adrià Arrufat
4307509094 agent: improve REPL syntax highlighting and terminal colors
- Add highlighting for JS functions, methods, types, and template
  interpolations.
- Introduce teal color and adjust cyan to bright cyan.
- Import `ansi.zig` directly instead of through `Terminal`.
- Add PandaScript semantics note to the agent's system prompt.
- Refactor markdown table rendering and streaming.
2026-07-15 11:02:46 +02:00
Francis Bouvier
35cf234f21 webapi: innerHTML/outerHTML queue one combined mutation record
Fixes WPT /dom/nodes/MutationObserver-inner-outer.html (0/3 -> 3/3):
setting innerHTML must queue a single "replace all" mutation record
(all removed children + all parsed children), and setting outerHTML a
single record replacing the element with the parsed nodes. We emitted
one record per removed child plus one per inserted child.

- Node.setHTML suppresses per-node records (removals via the new
  notify_observers opt, insertions by making fragment parsing never
  notify) and queues the combined record itself. Parsing still targets
  the element directly so html5ever keeps the right fragment context
  (e.g. raw-text content of <script>).
- Fragment parsing no longer notifies observers per inserted child:
  every other fragment-parse target is a detached DocumentFragment
  where notification is a no-op.
- Element.setOuterHTML moves the parsed nodes in with notification
  suppressed and queues one record with removedNodes=[the element],
  addedNodes=parsed children and the element's siblings.
- The unit test mutation_observer/childlist.html expected the old
  6-record innerHTML behavior; updated to the spec's single record
  (matches Chrome).

Coverage: /dom/nodes/MutationObserver-inner-outer.html 0/3 -> 3/3
(fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:54:01 +08:00
Francis Bouvier
0ee54e3343 webapi: replace-all queues one combined mutation record
Fixes WPT /dom/nodes/MutationObserver-textContent.html (1/4) and the
remaining failures of ParentNode-replaceChildren.html (25/29): the DOM
"replace all" algorithm (Element.textContent setter,
ParentNode.replaceChildren) must queue a single tree mutation record
with all removedNodes and addedNodes (and null previous/next sibling).
We emitted one record per removed child plus one per added child, so
observers saw 2+ records where the spec requires exactly one.

Frame.removeNode/appendNode gain a notify_observers opt (default true);
Node.replaceChildren suppresses the per-node records and queues the
combined record itself. Removing an added child from its previous
parent still notifies that parent's observers separately, as the spec
requires.

Coverage:
- /dom/nodes/MutationObserver-textContent.html 1/4 -> 4/4 (fully green)
- /dom/nodes/ParentNode-replaceChildren.html 25/29 -> 29/29 (fully green)
- /dom/nodes/MutationObserver-childList.html 29/38 -> 30/38

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:54:01 +08:00
Francis Bouvier
575ca0000c webapi: invoke MutationObserver callbacks with the observer as this
Fixes WPT /dom/nodes/MutationObserver-callback-arguments.html: per the
DOM spec ("invoke callback with a list of MutationRecord objects and mo,
and mo as callback this value"), the mutation callback's this value must
be the MutationObserver itself. We invoked it with the default receiver
(undefined -> globalThis), so `this === mo` failed.

deliverRecords now uses tryCallWithThis with the observer as receiver.

Coverage: /dom/nodes/MutationObserver-callback-arguments.html 0/1 -> 1/1
(fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:54:00 +08:00
Francis Bouvier
a603721f5f webapi: insert-adjacent spec semantics; document pre-insert validity
Fixes all failing subtests of WPT /dom/nodes/Element-insertAdjacentElement.html
(1/6), Element-insertAdjacentText.html (5/6) and insert-adjacent.html (11/14):

- insertAdjacentElement/Text wrongly reused insertAdjacentHTML's rule of
  throwing NoModificationAllowedError for a null or document parent. Per
  DOM's insert-adjacent algorithm they instead return null (no-op) for a
  null parent and otherwise rely on pre-insert validity, so inserting
  before/after the document element reports HierarchyRequestError.
  findAdjacentNodes takes the variant; insertAdjacentHTML keeps its
  HTML-spec behavior.
- insertAdjacentElement now returns the inserted element (was void, so
  scripts using the return value got undefined).
- The pre-insert validity checks did not implement the document-parent
  rules: a document can't contain Text children and has at most one
  element child. validateDocumentInsertion enforces both in
  appendChild/insertBefore/replaceChild; replaceChild excludes the child
  being replaced from the single-element rule, and replaceChildren
  (which replaces every child) is intentionally unaffected.

Coverage:
- /dom/nodes/Element-insertAdjacentElement.html 1/6 -> 6/6 (fully green)
- /dom/nodes/Element-insertAdjacentText.html 5/6 -> 6/6 (fully green)
- /dom/nodes/insert-adjacent.html 11/14 -> 14/14 (fully green)
- /dom/nodes/Node-insertBefore.html 13/40 -> 16/40
- /dom/nodes/Node-replaceChild.html 14/29 -> 15/29

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:54:00 +08:00
Karl Seguin
e3c41d152e Merge pull request #2951 from lightpanda-io/dom-pr-10-selectors-and-encoding
selector/webapi: :link/:lang/:empty semantics, document encoding, for-in enumerability
2026-07-15 16:43:38 +08:00
Karl Seguin
e5257f9bc3 Use node childrenIterator
Introduce node.ownerDocumentIncludingSelf() to remove duplicate logic through
Node.zig.
2026-07-15 16:27:28 +08:00
Francis Bouvier
d357f093c0 webapi: HTMLCollection named properties are not enumerable in for-in
Fixes the failing subtest of WPT /dom/nodes/Element-children.html
("HTMLCollection edge cases 1"): iterating an HTMLCollection with
for-in must yield only the supported indices; the supported names are
[LegacyUnenumerableNamedProperties] and must be skipped, while
Object.getOwnPropertyNames still returns indices + names.

v8 filters for-in through the named query interceptor, which
HTMLCollection did not register (only a descriptor callback), so every
name reported by the enumerator was treated as enumerable.

HTMLCollection now registers a named query reporting DontEnum for
supported names. The query deliberately does not report ReadOnly: v8
also consults it when a [[Set]] walks the prototype chain, and a
read-only property on the prototype would block the shadowing expando
that the spec's ignore-named-props rule requires
(HTMLCollection-as-prototype.html). Writability as observed through
getOwnPropertyDescriptor still comes from the descriptor callback, and
direct assignments to supported names still fail through the definer.

Coverage: /dom/nodes/Element-children.html 1/2 -> 2/2 (fully green);
/dom/collections stays fully green (53/53).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 15:53:34 +08:00
Francis Bouvier
152f1eb8eb webapi: script-created documents are UTF-8; URLs use the document encoding
Fixes the last failing subtest of WPT
/dom/nodes/DOMImplementation-createHTMLDocument.html ("URL parsing"):
resolving `a.href = "http://example.org/?ä"` on an anchor inside a
createHTMLDocument() document returned "?%E4" instead of "?%C3%A4".

Two spec violations combined:

- Per DOM, documents synthesized by script (createHTMLDocument,
  createDocument, new Document()) have the UTF-8 encoding. We had no
  per-document encoding at all: document.characterSet always reflected
  the frame's charset, so the new document inherited windows-1252 from
  the test page (which uses that encoding deliberately to catch this).
  Document gains a _charset override (same pattern as _content_type),
  set to UTF-8 in DOMImplementation.createHTMLDocument/createDocument
  and the Document constructor.

- Node.resolveURL encoded the query string with the frame's charset.
  Per the URL/HTML specs the query percent-encoding uses the encoding
  of the element's node document, so it now resolves the owning
  document and uses its encoding, falling back to the frame's.

Coverage:
- /dom/nodes/DOMImplementation-createHTMLDocument.html 12/13 -> 13/13
  (fully green)
- /dom/nodes/Document-constructor.html 3/5 -> 4/5

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 15:53:34 +08:00
Francis Bouvier
fd174986cf selector: implement :link, :lang, :empty spec semantics; parser fixes
Fixes the remaining 30 failing subtests of WPT
/dom/nodes/Element-matches.html, in five clusters:

Matching (selector/List.zig):

- :link now matches a and area elements with an href attribute (in a
  headless browser no link is ever visited, so :visited stays
  unmatched and :link covers every hyperlink). :any-link gains the
  missing area case.
- :empty now ignores comment and processing-instruction children, per
  Selectors Level 3 only elements and non-empty text/cdata affect
  emptiness (<p><!-- comment --></p> is :empty, <p> </p> is not).
- :lang() is implemented: the element's language is the nearest
  ancestor-or-self lang attribute, falling back to the UA default (en)
  for elements in a document and to no language at all in detached
  subtrees, which is what the WPT expects for the detached/fragment
  contexts. Matching is ASCII case-insensitive on the exact tag or a
  `-` separated prefix (:lang(en) matches lang="en-AU").

Parsing (selector/Parser.zig):

- An empty selector-list segment ("div," or ",div") is now a parse
  error instead of being silently skipped.
- Unexpected EOF closes open attribute brackets per CSS Syntax:
  '#attr-value [align="center"' parses and matches.
- Attribute selectors accept a namespace component: [*|TiTlE] (any
  namespace) and [|title] (no namespace). Attributes are stored by
  qualified name and almost never namespaced, so both forms match by
  name; [*|*=test] stays invalid.

Coverage:
- /dom/nodes/Element-matches.html 639/669 -> 669/669 (fully green)
- /dom/nodes/ParentNode-querySelectors-namespaces.html 0/1 -> 1/1
- /dom/nodes/moveBefore/moveBefore-lang.html 0/1 -> 1/1
- /dom/nodes/moveBefore/Node-moveBefore.html 31/32 -> 32/32

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 15:53:33 +08:00
Karl Seguin
78fbe2f1f3 Merge pull request #2950 from lightpanda-io/dom-pr-09-event-types-and-realms
webapi: new event interfaces, HTML-namespace naming, realm-correct exceptions
2026-07-15 15:51:52 +08:00
Adrià Arrufat
683b9b412b md_term: render styled borders for fenced code blocks
Adds top and bottom borders around code blocks, displaying the language
tag if present. Also changes horizontal rules to dashed lines to
distinguish them from code block borders.
2026-07-15 09:49:59 +02:00
Karl Seguin
926536fe18 Merge pull request #2918 from lightpanda-io/finalize-more-types
mem: Finalize more (non-dom) types
2026-07-15 15:32:24 +08:00
Karl Seguin
58f5f857d9 Detect Node-types that don't have an asNode()
Don't set null_as_undefined = false..it's the default.
2026-07-15 15:30:49 +08:00
Adrià Arrufat
813cf7f424 agent: clean up terminal rendering and highlighting
- Extract ANSI escape codes to a dedicated `ansi.zig` module.
- Consolidate styled output rendering in `Terminal.zig`.
- Simplify dollar variable highlighting and table measurement.
2026-07-15 09:25:33 +02:00
Adrià Arrufat
8b1686f6fb agent: highlight markdown code blocks as JS
Extracts the JavaScript highlighting logic from `Terminal.zig` into a
reusable `js_highlight.zig` module. Uses this module to syntax-highlight
markdown fenced code blocks in `md_term.zig` using ANSI escape codes.
2026-07-15 09:10:11 +02:00
Karl Seguin
cd7b63cade mem: Finalize more (non-dom) types
Adds finalizers to various types. The two most interesting are ImageData (which
could have a large data field) and HTMLCollection which a page could create
many.

Various Crypto types are also finalized to make sure the key is freed. This is
particularly important for freeing any keys created with EVP_PKEY_new.
2026-07-15 14:51:35 +08:00
Karl Seguin
2edc2eb131 perf: Pre-parse HTML to find and preload scripts
Builds on top of the recently added support for <link rel=preload...> and
<link rel=modulePreload...> to scan the HTML for script tags to preload. I.e.
adds script preloading without actually having any preload hits.

At least for this first pass, I opted for a simple approach which leverages
are fully buffered HTML body and html5ever's tokenizer to prescan the body and
kickoff any script fetching before starting the complete parse.

There are doubtless cases where this will either decrease performance and/or
increase memory usage. E.g. a site with no script gets its html scanned twice
and loading multiple blocking scripts in parallel obvious uses more memory
than loading them sequentially. But for most sites and I think most use-cases,
the impact should range between neutral to significantly faster loads.

This is something most browsers do.
2026-07-15 14:36:23 +08:00
Adrià Arrufat
3083414798 terminal: use standard SGR dim and cyan code blocks
Replaces the 256-color gray escape sequence with standard SGR 2 dim.
Also updates fenced code blocks to render in cyan instead of dim.
2026-07-15 08:02:51 +02:00
Francis Bouvier
945c6d40cb js: create thrown exceptions in the receiver's relevant realm
Fixes the 34 "wrong global" failures in WPT /dom/nodes/Element-matches.html
(and the equivalent checks in the other selector test files): when a DOM
method is called on a node from another realm (the test roots live in an
iframe), the thrown exception must be created in the receiver's relevant
realm, per Web IDL's "create an exception" using the context object's
realm. The harness checks e.constructor === root.ownerDocument.defaultView
.DOMException, which failed because we always built exceptions in the
caller's context.

The creation context of the wrapper can't be used to find that realm:
wrappers are session-level (one JS wrapper per Zig object, shared across
same-origin contexts). Instead, handleError now resolves the receiver
DOM node's document frame: for functions whose receiver is a Node (or a
type with an asNode() cast), errorLocal maps this -> node -> ownerDocument
-> frame, and if that frame differs from the calling one, the error is
constructed inside that frame's v8 context (entered/exited around the
exception creation).

TaggedOpaque.fromJS also learns to reject objects whose internal field
does not hold an aligned TaggedOpaque pointer. Such objects exist: a
custom element whose constructor throws was created from our template
but never mapped to a Zig instance, and its internal field still holds a
v8 tagged value. errorLocal probes the receiver on every error path, so
without the check the @alignCast panics (caught by the unit test suite's
custom_elements constructor.html).

Coverage: /dom/nodes/Element-matches.html 605/669 -> 639/669.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 12:59:53 +08:00
Francis Bouvier
12eb192815 webapi: only HTML-namespace elements are named by their name attribute
Fixes the failing subtest "hasOwnProperty, getOwnPropertyDescriptor,
getOwnPropertyNames" in WPT /dom/nodes/Document-getElementsByTagName.html
(17/18 -> 18/18) and /dom/nodes/Element-getElementsByTagName.html
(18/19 -> 19/19).

Per the DOM spec's supported property names for HTMLCollection, the
name attribute only exposes elements in the HTML namespace (ids expose
any element). The live-collection getByName fallback matched any
element with a name attribute; it now skips non-HTML elements, matching
the enumerator which already had the guard.

Coverage: Document-getElementsByTagName.html 17/18 -> 18/18,
Element-getElementsByTagName.html 18/19 -> 19/19. /dom/collections
stays fully green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 12:59:52 +08:00
Francis Bouvier
7f04ee5f0a webapi: add BeforeUnload/Storage/DeviceMotion/DeviceOrientation/Touch events
Fixes all 21 failing tests in WPT /dom/nodes/Document-createEvent.https.html
(258/279 -> 279/279), Document-createEvent-touchevent.window.html
(0/3 -> 3/3) and, as a side effect, /dom/events/non-cancelable-when-
passive/synthetic-events-cancelable.html (8/12 -> 12/12).

- Five new event interfaces, following the existing patterns:
  BeforeUnloadEvent (returnValue, no constructor per spec), StorageEvent
  (key/oldValue/newValue/url + initStorageEvent; storageArea is always
  null), DeviceMotionEvent and DeviceOrientationEvent (nullable sensor
  values), and TouchEvent (UIEvent subclass with modifier keys and empty
  touch lists — there is no touch input source).
- document.createEvent maps their aliases to real instances instead of
  plain Events, adds "touchevent", and drops the non-spec pluralized
  aliases CustomEvents/FocusEvents/TextEvents, which must throw
  NotSupportedError (the unit test asserting the old behavior is
  updated).
- The "expose legacy touch event APIs" precondition requires
  ontouchstart & co. to exist: the four touch handlers are added to the
  global event handler set, HTMLElement and Document.

Coverage: /dom/nodes/Document-createEvent.https.html 258/279 ->
279/279, Document-createEvent-touchevent.window.html 0/3 -> 3/3,
synthetic-events-cancelable.html 8/12 -> 12/12. No regressions across
/dom/events; 1002/1002 unit tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 12:59:52 +08:00
Karl Seguin
58d8aeb070 Merge pull request #2949 from lightpanda-io/dom-pr-08-idl-and-namespaces
webapi: IDL argument shapes, DOMTokenList reflection, namespace validation
2026-07-15 12:57:55 +08:00
Karl Seguin
872580a708 Move logic out of JsAPI
While we do sometimes write functions directly in the JsAPI bridge, this is
usually limited to things that are clearly JS/v8 bridging related. None of the
new getters fit this (admittedly loose) definition..they're accessors like any
other.
2026-07-15 12:39:10 +08:00
Karl Seguin
a18886b1a9 cleanup: Enhance preload scripts
This fixes a bug with preload script so that they're actually used for
async/defer scripts (previously, only used for blocking scripts).

More importantly, this cleans up the ScriptManager's addFromElement. For example
inline scripts are handled in their own function, which means we aren't weaving
the two modes in a single function. It also allows the inline-script to use
a better-sized arena. The goal for this cleanup is the follow up commit which
will bring a pre-parse step to preload scripts without an explicit <link> hint.
2026-07-15 12:04:26 +08:00
Karl Seguin
8f26f1e4b7 zig fmt 2026-07-15 12:03:46 +08:00
Francis Bouvier
aba796eb36 webapi: implement validate-and-extract; real namespace URIs
Fixes 158 failing tests in WPT
/dom/nodes/DOMImplementation-createDocument.html (276/434 -> 434/434)
and improves Document-createElementNS.html (82/596 -> 197/596),
Document-createElement.html (29/147 -> 34/147),
Document-contentType/createDocument.html (0/1 -> 1/1) and
name-validation.html (0/5 -> 2/5). The remaining failures in those
files need XML/XHTML document loading, which Lightpanda doesn't have.

- Document now implements the DOM spec's §1.4 name validation
  productions (valid element/attribute local name, valid namespace
  prefix) and the "validate and extract" algorithm, replacing the
  older ad-hoc element name check: prefixes are validated, and the
  prefix/namespace consistency rules throw NamespaceError (prefix
  without namespace, xml/xmlns mismatches).
- createElementNS and DOMImplementation.createDocument route through
  it. createDocument also now: treats its two first arguments as
  required (namespace via the js.Nullable wrapper, qualifiedName as a
  raw js.Value so [LegacyNullToEmptyString] null maps to "" while
  undefined stringifies), sets the spec's namespace-dependent
  contentType, and registers custom namespace URIs for the root
  element.
- element.namespaceURI now returns the actual URI for namespaces
  outside the built-in set (it returned a lightpanda.io placeholder),
  and Element.clone copies the registration. The unit tests asserting
  the placeholder are updated to the correct values.

Coverage: DOMImplementation-createDocument.html 276/434 -> 434/434 and
the improvements above. No regressions across /dom/nodes; 1002/1002
unit tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 12:02:36 +08:00
Francis Bouvier
4c306d50b7 webapi: DOMImplementation owns its document; validate doctype names
Fixes 81 failing tests in WPT
/dom/nodes/DOMImplementation-createDocumentType.html (1/82 -> 82/82):

- DOMImplementation was an empty singleton-style object with no link to
  its document, so a doctype created through another document's
  implementation (e.g. createHTMLDocument().implementation) reported
  the frame's main document as its ownerDocument. The implementation
  object now stores its associated document and registers created
  doctypes in the frame's node-owner-document map, following the
  createDocumentFragment pattern.
- createDocumentType now validates the qualified name against the
  doctype name production (no ASCII whitespace or '>'), throwing
  InvalidCharacterError.

Coverage: /dom/nodes/DOMImplementation-createDocumentType.html 1/82 ->
82/82.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 11:59:57 +08:00
Francis Bouvier
0a7e24fa2f webapi: DOMTokenList-reflected attributes on area, output, iframe, link
Fixes 4 failing tests in WPT
/dom/lists/DOMTokenList-coverage-for-attributes.html (135/140 ->
139/140): area.relList, output.htmlFor, iframe.sandbox and link.sizes
must be DOMTokenList attributes reflecting their content attributes.

Element gains a generic getTokenList lookup (keyed by element and
attribute) alongside the existing class/rel dedicated ones, and the
four elements expose the accessors following the Anchor/Link relList
pattern (undefined outside the HTML namespace).

The remaining failure needs an SVGAElement interface (relList on SVG
<a> elements), which doesn't exist yet — SVG elements are all generic.

Coverage: /dom/lists/DOMTokenList-coverage-for-attributes.html
135/140 -> 139/140.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 11:59:56 +08:00
Francis Bouvier
0740f7d113 js: required-but-nullable arguments; fix EventTarget/AbortSignal IDL shape
Fixes 6 failing tests in WPT /dom/idlharness.any.worker.html
(211/219 -> 217/219) and the same assertions in the other idlharness
variants:

- addEventListener/removeEventListener had .length 1 instead of 2 and
  accepted being called with a single argument. Per Web IDL their
  callback parameter is required but nullable ("EventListener?"), which
  a plain Zig optional can't express (the bridge treats optionals as
  omittable and stops counting length at the first one). The new
  js.Nullable(T) wrapper marks a required argument that accepts null or
  undefined: omitting it throws a TypeError and it counts towards the
  function's length.
- new AbortSignal() didn't throw: the spec defines no constructor, so
  the JsApi constructor is removed (the interface object now uses the
  illegal-constructor callback; AbortSignal.init stays for internal
  use).
- AbortSignal.any() with no argument didn't throw: the trailing slice
  parameter was treated as variadic and defaulted to empty. The
  parameter is now a required js.Value converted to the signal sequence
  explicitly.

The 2 remaining failures need strict-mode receiver validation on the
flattened worker global and the DOMStringList interface.

Coverage: /dom/idlharness.any.worker.html 211/219 -> 217/219. No
regressions across /dom/events and /dom/abort.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 11:58:44 +08:00
Karl Seguin
7ee249a625 Merge pull request #2948 from lightpanda-io/dom-pr-07-click-activation-passive
webapi: click activation, shadow retargeting, passive-by-default listeners
2026-07-15 11:58:13 +08:00