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.
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/Stringvalues or asArray[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
IsNodedeclares:The FFI returns the raw browser values without conversion.
However:
nodeValueisnullfor nodes such asElementandDocument.firstChildandlastChildarenullwhen no child exists.References: Node.nodeValue, Node.firstChild.
Text nodes declared as Element
Document::create_text_nodereturnsElement, althoughdocument.createTextNodereturns aTextnode, not anElement.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_childrenreturnsArray[Element], but its FFI returnsself.childrendirectly.Element.childrenis a liveHTMLCollection, not a JavaScript Array. Array methods such asmapare therefore not available. The nearbyquery_selector_allbinding already handles this correctly withArray.from(...).Reference: HTMLCollection.
Expected behavior
@js.Nullable[T]orOption[T], consistently with sibling/parent bindings.create_text_node.childrenwithArray.from, or expose an explicit HTMLCollection wrapper rather than claiming it is an Array.Suggested tests
firstChildandlastChildon an empty element.nodeValueon an Element.get_children().map(...)works if the return type remainsArray[Element]..mbtifiles.