Skip to content

DOM bindings expose nullable and non-Array browser values with unsound types #132

Description

@yorkin-bot

Summary

Several public DOM bindings declare stronger MoonBit types than the browser APIs actually return. This allows null values and non-Array collections to cross the FFI boundary as non-null Node/String values or as Array[Element].

These declarations can turn ordinary DOM states into runtime failures in otherwise type-checked code.

Affected bindings

Nullable Node values declared as non-null

IsNode declares:

fn get_node_value(Self) -> String
fn get_first_child(Self) -> Node
fn get_last_child(Self) -> Node

The FFI returns the raw browser values without conversion.

However:

  • nodeValue is null for nodes such as Element and Document.
  • firstChild and lastChild are null when no child exists.

References: Node.nodeValue, Node.firstChild.

Text nodes declared as Element

Document::create_text_node returns Element, although document.createTextNode returns a Text node, not an Element.

This lets callers type-check Element-only operations against a Text node and then fail in JavaScript.

Reference: Document.createTextNode.

HTMLCollection declared as Array

IsElement::get_children returns Array[Element], but its FFI returns self.children directly.

Element.children is a live HTMLCollection, not a JavaScript Array. Array methods such as map are therefore not available. The nearby query_selector_all binding already handles this correctly with Array.from(...).

Reference: HTMLCollection.

Expected behavior

  • Represent nullable browser results with @js.Nullable[T] or Option[T], consistently with sibling/parent bindings.
  • Return a proper Text/Node type from create_text_node.
  • Convert children with Array.from, or expose an explicit HTMLCollection wrapper rather than claiming it is an Array.

Suggested tests

  • firstChild and lastChild on an empty element.
  • nodeValue on an Element.
  • Element-only operations are not available on a created Text node.
  • get_children().map(...) works if the return type remains Array[Element].
  • Verify that any public signature changes are reflected in generated .mbti files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions