js,jsdom: make JS structs plain objects; add more DOM API support for jsdom (#12501)
parent
409321327b
commit
1edb3e559e
|
@ -131,8 +131,270 @@ mut:
|
||||||
y JS.Number
|
y JS.Number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[use_new]
|
||||||
|
pub fn JS.DOMRect.prototype.constructor(x JS.Number, y JS.Number, width JS.Number, height JS.Number) JS.DOMRect
|
||||||
|
|
||||||
pub interface JS.DOMStringList {
|
pub interface JS.DOMStringList {
|
||||||
length JS.Number
|
length JS.Number
|
||||||
contains(JS.String) JS.Boolean
|
contains(JS.String) JS.Boolean
|
||||||
item(index JS.Number) ?JS.String
|
item(index JS.Number) ?JS.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub interface JS.DOMRectList {
|
||||||
|
length JS.Number
|
||||||
|
contains(JS.String) JS.Boolean
|
||||||
|
item(index JS.Number) ?JS.Rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DOMTokenListForEachCb = fn (JS.String, JS.Number, JS.DOMTokenList)
|
||||||
|
|
||||||
|
pub interface JS.DOMTokenList {
|
||||||
|
length JS.Number
|
||||||
|
toString() JS.String
|
||||||
|
add(tokens ...JS.Any) ?JS.Any
|
||||||
|
contains(token JS.String) JS.Boolean
|
||||||
|
item(index JS.Number) ?JS.String
|
||||||
|
remove(tokens ...JS.Any) ?JS.Any
|
||||||
|
replace(token JS.String, newToken JS.String) JS.Boolean
|
||||||
|
supports(token JS.String) JS.Boolean
|
||||||
|
toggle(token JS.String, force JS.Boolean) JS.Boolean
|
||||||
|
forEach(cb DOMTokenListForEachCb, thisArg JS.Any)
|
||||||
|
mut:
|
||||||
|
value JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.EventListenerOptions {
|
||||||
|
capture bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.EventTarget {
|
||||||
|
addEventListener(cb EventCallback, options JS.EventListenerOptions)
|
||||||
|
dispatchEvent(event JS.Event) JS.Boolean
|
||||||
|
removeEventListener(cb EventCallback, options JS.EventListenerOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event is an event which takes place in the DOM.
|
||||||
|
pub interface JS.Event {
|
||||||
|
JS.EventTarget
|
||||||
|
bubbles JS.Boolean
|
||||||
|
cancelable JS.Boolean
|
||||||
|
composed JS.Boolean
|
||||||
|
currentTarget JS.EventTarget
|
||||||
|
defaultPrevented JS.Boolean
|
||||||
|
eventPhase JS.Number
|
||||||
|
isTrusted JS.Boolean
|
||||||
|
srcElement JS.EventTarget
|
||||||
|
timeStamp JS.DOMHighResTimeStamp // composedPath returns the invocation target objects of event's path.
|
||||||
|
composedPath() JS.Array
|
||||||
|
initEvent(typ JS.String, bubbles JS.Boolean, cancelable JS.Boolean)
|
||||||
|
preventDefault()
|
||||||
|
stopImmediatePropagation()
|
||||||
|
stopPropagation()
|
||||||
|
mut:
|
||||||
|
returnValue JS.Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_type(ev JS.Event) string {
|
||||||
|
res := ''
|
||||||
|
#res.str = ev.type;
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_event(typ string, bubbles bool, cancelable bool, composed bool) JS.Event {
|
||||||
|
mut ev := JS.Event(voidptr(0))
|
||||||
|
#ev = new Event(typ.str,bubbles.val,cancelable.val,composed.val);
|
||||||
|
|
||||||
|
return ev
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.UIEvent {
|
||||||
|
JS.Event
|
||||||
|
detail JS.Number
|
||||||
|
view JS.Any
|
||||||
|
}
|
||||||
|
|
||||||
|
[use_new]
|
||||||
|
pub fn JS.UIEvent.prototype.constructor(typ JS.String, dict JS.UIEventDict) JS.UIEvent
|
||||||
|
|
||||||
|
pub struct JS.EventInit {
|
||||||
|
bubbles JS.Boolean
|
||||||
|
cancelable JS.Boolean
|
||||||
|
composed JS.Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.UIEventInitDict {
|
||||||
|
bubbles JS.Boolean
|
||||||
|
cancelable JS.Boolean
|
||||||
|
composed JS.Boolean
|
||||||
|
detail JS.Number
|
||||||
|
view JS.Any
|
||||||
|
which JS.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.MouseEvent {
|
||||||
|
JS.UIEvent
|
||||||
|
altKey JS.Boolean
|
||||||
|
button JS.Number
|
||||||
|
buttons JS.Number
|
||||||
|
clientX JS.Number
|
||||||
|
clientY JS.Number
|
||||||
|
ctrlKey JS.Number
|
||||||
|
metaKey JS.Number
|
||||||
|
movementX JS.Number
|
||||||
|
movementY JS.Number
|
||||||
|
offsetX JS.Number
|
||||||
|
offsetY JS.Number
|
||||||
|
pageX JS.Number
|
||||||
|
pageY JS.Number
|
||||||
|
relatedTarget JS.Any
|
||||||
|
screenX JS.Number
|
||||||
|
screenY JS.Number
|
||||||
|
shiftKey JS.Boolean
|
||||||
|
x JS.Number
|
||||||
|
y JS.Number
|
||||||
|
getModifierState(keyArg JS.String) JS.Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.Node {
|
||||||
|
JS.EventTarget
|
||||||
|
baseURI JS.String
|
||||||
|
childNodes JS.Any
|
||||||
|
firstChild JS.ChildNode
|
||||||
|
isConnected JS.Boolean
|
||||||
|
lastChild JS.ChildNode
|
||||||
|
nextSibling JS.ChildNode
|
||||||
|
nodeName JS.String
|
||||||
|
nodeType JS.Number
|
||||||
|
ownerDocument JS.Document
|
||||||
|
parentElement JS.HTMLElement
|
||||||
|
parentNode JS.ParentNode
|
||||||
|
previousSibling JS.ChildNode
|
||||||
|
appendChild(node JS.Node) JS.Node
|
||||||
|
cloneNode(deep JS.Boolean) JS.Node
|
||||||
|
compareDocumentPosition(other JS.Node) JS.Number
|
||||||
|
contains(other JS.Node) JS.Boolean
|
||||||
|
getRootNode(composed JS.Boolean) JS.Node
|
||||||
|
hasChildNodes() JS.Boolean
|
||||||
|
insertBefore(node JS.Node, child JS.Node) JS.Node
|
||||||
|
isEqualNode(otherNode JS.Node) JS.Boolean
|
||||||
|
isSameNode(otherNode JS.Node) JS.Boolean
|
||||||
|
lookupPrefix(namespace JS.String) JS.String
|
||||||
|
normalize()
|
||||||
|
removeChild(child JS.Node) JS.Node
|
||||||
|
replaceChild(node JS.Node, child JS.Node) JS.Npde
|
||||||
|
mut:
|
||||||
|
nodeValue JS.String
|
||||||
|
textContent JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.ChildNode {
|
||||||
|
JS.Node
|
||||||
|
after(nodes ...JS.Any)
|
||||||
|
before(nodes ...JS.Any)
|
||||||
|
remove()
|
||||||
|
replaceWith(nodes ...JS.Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.ParentNode {
|
||||||
|
JS.Node
|
||||||
|
childElementCount JS.Number
|
||||||
|
children JS.HTMLCollection
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.Document {
|
||||||
|
JS.Node
|
||||||
|
all JS.HTMLAllCollection
|
||||||
|
anchros JS.HTMLCollection
|
||||||
|
applets JS.HTMLCollection
|
||||||
|
characterSet JS.String
|
||||||
|
charset JS.String
|
||||||
|
compatMode JS.String
|
||||||
|
contentType JS.String
|
||||||
|
documentURI JS.String
|
||||||
|
documentElement JS.HTMLElement
|
||||||
|
hidden JS.Boolean
|
||||||
|
head JS.HTMLHeadElement
|
||||||
|
fullscreenEnabled JS.Boolean
|
||||||
|
fullscreen JS.Boolean
|
||||||
|
lastModified JS.String
|
||||||
|
inputEncoding JS.String
|
||||||
|
implementation JS.DOMImplementation
|
||||||
|
mut:
|
||||||
|
bgColor JS.String
|
||||||
|
body JS.HTMLElement
|
||||||
|
cookie JS.String
|
||||||
|
domain JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.PointerEvent {
|
||||||
|
JS.MouseEvent
|
||||||
|
height JS.Number
|
||||||
|
isPrimary JS.Boolean
|
||||||
|
pointerId JS.Number
|
||||||
|
pointerType JS.String
|
||||||
|
pressure JS.Number
|
||||||
|
tangentialPressure JS.Number
|
||||||
|
tiltX JS.Number
|
||||||
|
tiltY JS.Number
|
||||||
|
twist JS.Number
|
||||||
|
width JS.Number
|
||||||
|
getCoalescedEvents() JS.Array
|
||||||
|
getPredictedEvents() JS.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.Element {
|
||||||
|
JS.Node
|
||||||
|
classList JS.DOMTokenList
|
||||||
|
clientHeight JS.Number
|
||||||
|
clientLeft JS.Number
|
||||||
|
clientTop JS.Number
|
||||||
|
clientWidth JS.Number
|
||||||
|
localName JS.String
|
||||||
|
namespaceURI JS.String
|
||||||
|
ownerDocument JS.Document
|
||||||
|
part JS.DOMTokenList
|
||||||
|
prefix JS.String
|
||||||
|
scrollHeight JS.Number
|
||||||
|
scrollWidth JS.Number
|
||||||
|
tagName JS.String
|
||||||
|
closest(selector JS.String) ?JS.Element
|
||||||
|
getAttribute(qualifiedName JS.String) ?JS.String
|
||||||
|
getAttributeNS(namespace JS.String, localName JS.String) ?JS.String
|
||||||
|
getAttributeNames() JS.Array
|
||||||
|
getClientRects() JS.DOMRectList
|
||||||
|
getBoundingClientRect() JS.DOMRect
|
||||||
|
scrollTo(x JS.Number, y JS.Number)
|
||||||
|
scroll(x JS.Number, y JS.Number)
|
||||||
|
scrollBy(x JS.Number, y JS.Number)
|
||||||
|
toggleAttribute(qualifiedName JS.String, force JS.Boolean) JS.Boolean
|
||||||
|
mut:
|
||||||
|
className JS.String
|
||||||
|
id JS.String
|
||||||
|
onfullscreenchange fn (this JS.Element, ev JS.Event) JS.Any
|
||||||
|
onfullscreenerror fn (this JS.Element, ev JS.Event) JS.Any
|
||||||
|
outerHTML JS.String
|
||||||
|
scrollLeft JS.Number
|
||||||
|
scrollTop JS.Number
|
||||||
|
slot JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const (
|
||||||
|
document = JS.Document{}
|
||||||
|
)
|
||||||
|
|
||||||
|
fn init() {
|
||||||
|
#jsdom__document = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type EventCallback = fn (JS.Event)
|
||||||
|
|
||||||
|
// event_listener returns proper listener callback. This function is useful when you need access to `this` value
|
||||||
|
// that is EventTarget. When you need access only to Event itself you can just use `fn (JS.Event)` as listener.
|
||||||
|
pub fn event_listener(callback fn (JS.EventTarget, JS.Event)) EventCallback {
|
||||||
|
return fn [callback] (event JS.Event) {
|
||||||
|
mut target := JS.EventTarget(voidptr(0))
|
||||||
|
#target = this;
|
||||||
|
callback(target, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -567,8 +567,9 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
|
||||||
c.ensure_type_exists(param.typ, param.pos) or { return }
|
c.ensure_type_exists(param.typ, param.pos) or { return }
|
||||||
if is_js {
|
if is_js {
|
||||||
ptyp := c.table.get_type_symbol(param.typ)
|
ptyp := c.table.get_type_symbol(param.typ)
|
||||||
if ptyp.kind != .function && ptyp.language != .js
|
if (ptyp.kind != .function && ptyp.language != .js
|
||||||
&& !ptyp.name.starts_with('JS.') {
|
&& !ptyp.name.starts_with('JS.')) && !(j == method.params.len - 1
|
||||||
|
&& method.is_variadic) {
|
||||||
c.error('method `$method.name` accepts non JS type as parameter',
|
c.error('method `$method.name` accepts non JS type as parameter',
|
||||||
method.pos)
|
method.pos)
|
||||||
}
|
}
|
||||||
|
@ -594,7 +595,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
|
||||||
c.ensure_type_exists(field.typ, field.pos) or { return }
|
c.ensure_type_exists(field.typ, field.pos) or { return }
|
||||||
if is_js {
|
if is_js {
|
||||||
tsym := c.table.get_type_symbol(field.typ)
|
tsym := c.table.get_type_symbol(field.typ)
|
||||||
if tsym.language != .js && !tsym.name.starts_with('JS.') {
|
if tsym.language != .js && !tsym.name.starts_with('JS.') && tsym.kind != .function {
|
||||||
c.error('field `$field.name` uses non JS type', field.pos)
|
c.error('field `$field.name` uses non JS type', field.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3153,8 +3154,8 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to
|
||||||
// `none` "implements" the Error interface
|
// `none` "implements" the Error interface
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if typ_sym.kind == .interface_ && inter_sym.kind == .interface_ && styp != 'JS.Any'
|
if typ_sym.kind == .interface_ && inter_sym.kind == .interface_ && !styp.starts_with('JS.')
|
||||||
&& inter_sym.name != 'JS.Any' {
|
&& !inter_sym.name.starts_with('JS.') {
|
||||||
c.error('cannot implement interface `$inter_sym.name` with a different interface `$styp`',
|
c.error('cannot implement interface `$inter_sym.name` with a different interface `$styp`',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ fn (mut g JsGen) js_call(node ast.CallExpr) {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
if call_return_is_optional {
|
if call_return_is_optional {
|
||||||
g.write(';\n')
|
g.write(';\n')
|
||||||
g.writeln('if (tmp === null || tmp === undefined) throw "none";')
|
g.writeln('if (tmp === null) throw "none";')
|
||||||
g.writeln('return tmp;')
|
g.writeln('return tmp;')
|
||||||
g.writeln('} catch(err) {')
|
g.writeln('} catch(err) {')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
|
@ -140,7 +140,7 @@ fn (mut g JsGen) js_method_call(node ast.CallExpr) {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
if call_return_is_optional {
|
if call_return_is_optional {
|
||||||
g.write(';\n')
|
g.write(';\n')
|
||||||
g.writeln('if (tmp === null || tmp === undefined) throw "none";')
|
g.writeln('if (tmp === null) throw "none";')
|
||||||
g.writeln('return tmp;')
|
g.writeln('return tmp;')
|
||||||
g.writeln('} catch(err) {')
|
g.writeln('} catch(err) {')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
|
|
|
@ -3091,9 +3091,12 @@ fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
||||||
}
|
}
|
||||||
g.expr(it.expr)
|
g.expr(it.expr)
|
||||||
mut ltyp := it.expr_type
|
mut ltyp := it.expr_type
|
||||||
for ltyp.is_ptr() {
|
lsym := g.table.get_type_symbol(ltyp)
|
||||||
g.write('.val')
|
if lsym.kind != .interface_ && lsym.language != .js {
|
||||||
ltyp = ltyp.deref()
|
for ltyp.is_ptr() {
|
||||||
|
g.write('.val')
|
||||||
|
ltyp = ltyp.deref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.write('.$it.field_name')
|
g.write('.$it.field_name')
|
||||||
}
|
}
|
||||||
|
@ -3159,7 +3162,11 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
||||||
type_sym := g.table.get_type_symbol(it.typ)
|
type_sym := g.table.get_type_symbol(it.typ)
|
||||||
name := type_sym.name
|
name := type_sym.name
|
||||||
if it.fields.len == 0 && type_sym.kind != .interface_ {
|
if it.fields.len == 0 && type_sym.kind != .interface_ {
|
||||||
g.write('new ${g.js_name(name)}({})')
|
if type_sym.kind == .struct_ && type_sym.language == .js {
|
||||||
|
g.write('{}')
|
||||||
|
} else {
|
||||||
|
g.write('new ${g.js_name(name)}({})')
|
||||||
|
}
|
||||||
} else if it.fields.len == 0 && type_sym.kind == .interface_ {
|
} else if it.fields.len == 0 && type_sym.kind == .interface_ {
|
||||||
g.write('new ${g.js_name(name)}()') // JS interfaces can be instantiated with default ctor
|
g.write('new ${g.js_name(name)}()') // JS interfaces can be instantiated with default ctor
|
||||||
} else if type_sym.kind == .interface_ && it.fields.len != 0 {
|
} else if type_sym.kind == .interface_ && it.fields.len != 0 {
|
||||||
|
@ -3176,7 +3183,11 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('})()')
|
g.writeln('})()')
|
||||||
} else {
|
} else {
|
||||||
g.writeln('new ${g.js_name(name)}({')
|
if type_sym.kind == .struct_ && type_sym.language == .js {
|
||||||
|
g.writeln('{')
|
||||||
|
} else {
|
||||||
|
g.writeln('new ${g.js_name(name)}({')
|
||||||
|
}
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
for i, field in it.fields {
|
for i, field in it.fields {
|
||||||
g.write('$field.name: ')
|
g.write('$field.name: ')
|
||||||
|
@ -3187,7 +3198,11 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.write('})')
|
if type_sym.kind == .struct_ && type_sym.language == .js {
|
||||||
|
g.writeln('}')
|
||||||
|
} else {
|
||||||
|
g.writeln('})')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue