jsdom, js: start refactoring jsdom; improve JS interfaces; add two attributes for them (#12488)

pull/12490/head
playX 2021-11-17 12:41:33 +03:00 committed by GitHub
parent 6ac109a7c3
commit 2eb02ff5a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 282 additions and 1812 deletions

View File

@ -1,3 +1,4 @@
/*
import jsdom
fn get_2dcontext(canvas jsdom.IElement) ?jsdom.CanvasRenderingContext2D {
@ -74,3 +75,8 @@ fn main() {
context.clear_rect(0, 0, canv.width(), canv.height())
})
}
*/
fn main() {
panic('jsdom is being refactored; This example will be available soon')
}

View File

@ -397,3 +397,11 @@ pub fn (a []string) str() string {
res := sb.str()
return res
}
pub fn (a array) to_js_array() JS.Array {
tmp := JS.Array.prototype.constructor()
for i in 0 .. a.len {
tmp.push(a.arr.get(i))
}
return tmp
}

View File

@ -9,14 +9,17 @@ module builtin
pub interface JS.Object {}
[single_impl]
pub interface JS.BigInt {
JS.Any
}
[single_impl]
pub interface JS.Number {
JS.Any
}
[single_impl]
pub interface JS.String {
JS.Any
length JS.Number
@ -34,8 +37,10 @@ pub interface JS.String {
lastIndexOf(needle JS.String) JS.Number
}
[single_impl]
pub interface JS.Boolean {
JS.Any
length JS.Number
}
pub interface JS.Map {

View File

@ -17,7 +17,7 @@ pub fn (s string) runes() []rune {
}
pub fn (s string) slice(a int, b int) string {
return string(s.str.slice(a, b))
return string(s.str.slice(JS.Number(a), JS.Number(b)))
}
pub fn (s string) substr(start int, end int) string {
@ -88,7 +88,7 @@ pub fn (s string) split(dot string) []string {
pub fn (s string) bytes() []byte {
sep := ''
tmparr := s.str.split(sep.str).map(fn (it JS.Any) JS.Any {
return JS.Any(byte(JS.String(it).charCodeAt(0)))
return JS.Any(byte(JS.String(it).charCodeAt(JS.Number(0))))
})
_ := tmparr
mut arr := []byte{}
@ -98,8 +98,8 @@ pub fn (s string) bytes() []byte {
}
pub fn (s string) capitalize() string {
part := string(s.str.slice(1, int(s.str.length)))
return string(s.str.charAt(0).toUpperCase().concat(part.str))
part := string(s.str.slice(JS.Number(1), s.str.length))
return string(s.str.charAt(JS.Number(0)).toUpperCase().concat(part.str))
}
pub fn (s string) clone() string {

View File

@ -1,34 +0,0 @@
// Wrapper around 2d context and WebGL APIs
module jsdom
pub struct ContextAttributes {
pub:
alpha bool
desynchronized bool
}
pub enum PowerPreference {
default_
high_performance
low_performance
}
pub struct WebGLAttributes {
pub:
alpha bool
desynchronized bool
antialias bool
depth bool
fail_if_major_perf_caveat bool
power_preference PowerPreference
premultiplied_alpha bool
preserve_drawing_buffer bool
stencil bool
}
pub struct NoneContext {}
pub type ContextResult = CanvasRenderingContext2D | NoneContext | WebGLRenderingContext
pub struct JS.CanvasGradient {}

View File

@ -1,409 +0,0 @@
module jsdom
struct JS.CanvasRenderingContext2D {
mut:
lineWidth JS.Number
lineCap JS.String
lineJoin JS.String
miterLimit JS.Number
lineDashOffset JS.Number
font JS.String
textAlign JS.String
textBaseline JS.String
direction JS.String
fillStyle voidptr
strokeStyle voidptr
shadowBlur JS.Number
shadowColor JS.String
shadowOffsetX JS.Number
shadowOffsetY JS.Number
globalAlpha JS.Number
globalCompositeOperation JS.String
}
pub enum LineJoin {
bevel
round
miter
}
pub enum TextAlign {
left
right
center
start
end
}
pub struct CanvasRenderingContext2D {
mut:
ctx JS.CanvasRenderingContext2D [noinit]
}
pub type StrokeStyle = JS.CanvasGradient | string
pub fn (ctx CanvasRenderingContext2D) begin_path() {
#ctx.ctx.beginPath();
}
pub fn (ctx CanvasRenderingContext2D) set_line_dash(arr []f64) {
#let tmp = []
for x in arr {
#tmp.push(x.val);
_ := x
}
#ctx.ctx.setLineDash(tmp);
}
pub fn (ctx CanvasRenderingContext2D) get_line_dash() []f64 {
arr := []f64{}
#for (elem of ctx.ctx.getLineDash()) { array_push(arr,elem); }
return arr
}
pub fn (ctx CanvasRenderingContext2D) set_text_align(align TextAlign) {
match align {
.left {
#ctx.ctx.textAlign = 'start';
}
.right {
#ctx.ctx.textAlign = 'right';
}
.center {
#ctx.ctx.textAlign = 'center';
}
.start {
#ctx.ctx.textAlign = 'start';
}
.end {
#ctx.ctx.textAlign = 'end';
}
}
}
pub fn (ctx CanvasRenderingContext2D) set_line_join(j LineJoin) {
match j {
.bevel {
#ctx.ctx.lineJoin = 'bevel'
}
.round {
#ctx.ctx.lineJoin = 'round'
}
.miter {
#ctx.ctx.lineJoin = 'miter'
}
}
}
pub fn (ctx CanvasRenderingContext2D) set_stroke_style(style StrokeStyle) {
#ctx.ctx.strokeStyle = style instanceof string ? style.str : style
}
pub fn (ctx CanvasRenderingContext2D) set_fill_style(style StrokeStyle) {
#ctx.ctx.fillStyle = style instanceof string ? style.str : style
}
pub fn (ctx CanvasRenderingContext2D) line_width() f64 {
res := 0
#res.val = ctx.ctx.lineWidth
return res
}
pub fn (ctx CanvasRenderingContext2D) font() string {
res := ''
#res.str = ctx.ctx.font;
return res
}
pub fn (ctx CanvasRenderingContext2D) set_font(font string) {
#ctx.ctx.font = font.str;
}
pub fn (ctx CanvasRenderingContext2D) fill_rect(x f64, y f64, width f64, height f64) {
#ctx.ctx.fillRect(x.val,y.val,width.val,height.val)
}
pub fn (ctx CanvasRenderingContext2D) set_line_width(width f64) {
#ctx.ctx.lineWidth = width.val
}
pub fn (ctx CanvasRenderingContext2D) move_to(x f64, y f64) {
#ctx.ctx.moveTo(x.val,y.val);
}
pub fn (ctx CanvasRenderingContext2D) line_to(x f64, y f64) {
#ctx.ctx.lineTo(x.val,y.val);
}
pub fn (ctx CanvasRenderingContext2D) stroke() {
#ctx.ctx.stroke();
}
pub fn (ctx CanvasRenderingContext2D) close_path() {
#ctx.ctx.closePath();
}
pub fn (ctx CanvasRenderingContext2D) stroke_rect(x f64, y f64, width f64, height f64) {
#ctx.ctx.strokeRect(x.val,y.val,width.val,height.val);
}
pub fn (ctx CanvasRenderingContext2D) clear_rect(x f64, y f64, width f64, height f64) {
#ctx.ctx.clearRect(x.val,y.val,width.val,height.val);
}
pub fn (ctx CanvasRenderingContext2D) create_linear_gradient(x0 f64, y0 f64, x1 f64, y1 f64) JS.CanvasGradient {
return ctx.ctx.createLinearGradient(x0, y0, x1, y1)
}
pub fn (ctx CanvasRenderingContext2D) create_conic_gradient(start_angle f64, x f64, y f64) JS.CanvasGradient {
return ctx.ctx.createConicGradient(start_angle, x, y)
}
pub fn (ctx CanvasRenderingContext2D) create_radial_gradient(x0 f64, y0 f64, r0 f64, x1 f64, y1 f64, r1 f64) JS.CanvasGradient {
return ctx.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1)
}
pub fn (ctx CanvasRenderingContext2D) bezier_curve_to(cp1x f64, cp1y f64, cp2x f64, cp2y f64, x f64, y f64) {
#ctx.ctx.bezierCurveTo(cp1x.val,cp1y.val,cp2x.val,cp2y.val, x.val,y.val);
}
pub fn (ctx CanvasRenderingContext2D) quadratic_curve_to(cpx f64, cpy f64, x f64, y f64) {
#ctx.ctx.quadraticCurveTo(cpx.val,cpy.val,x.val,y.val);
}
pub fn (ctx CanvasRenderingContext2D) arc(x f64, y f64, radius f64, start_angle f64, end_angle f64, counter_clockwise bool) {
#ctx.ctx.arc(x.val,y.val,radius.val,start_angle.val,end_angle.val,counter_clockwise.val)
}
pub fn (ctx CanvasRenderingContext2D) arc_to(x1 f64, y1 f64, x2 f64, y2 f64, radius f64) {
#ctx.ctx.arcTo(x1.val,y1.val,x2.val,y2.val,radius.val);
}
pub fn (ctx CanvasRenderingContext2D) ellipse(x f64, y f64, radius_x f64, radius_y f64, rotation f64, start_angle f64, end_angle f64, counter_clockwise bool) {
#ctx.ctx.ellipse(x.val,y.val,radius_x.val,radius_y.val,rotation.val,start_angle.val,end_angle.val,counter_clockwise.val);
}
pub fn (ctx CanvasRenderingContext2D) rect(x f64, y f64, width f64, height f64) {
#ctx.ctx.rect(x.val,y.val,widht.val,height.val);
}
pub fn (ctx CanvasRenderingContext2D) draw_focus_if_needed(el IElement) {
#ctx.ctx.drawFocusIfNeeded(el.val.node);
}
pub fn (ctx CanvasRenderingContext2D) draw_focus_if_needed_wpath(path Path2D, el IElement) {
#ctx.ctx.drawFocusIfNeeded(path.path, el.val.node);
}
fn (ctx JS.CanvasRenderingContext2D) createRadialGradient(x0 f64, y0 f64, r0 f64, x1 f64, y1 f64, r1 f64) JS.CanvasGradient
fn (ctx JS.CanvasRenderingContext2D) createConicGradient(startAngle f64, x f64, y f64) JS.CanvasGradient
fn (ctx JS.CanvasRenderingContext2D) createLinearGradient(x0 f64, y0 f64, x1 f64, y1 f64) JS.CanvasGradient
pub fn (gradient JS.CanvasGradient) addColorStop(x f64, color string)
/// fill_text draws a text string at the specified coordinates. `max_width` allows specifying a maximum
/// width for the rendered text, set max_width to -1.0 to automatically adjust text width.
pub fn (ctx CanvasRenderingContext2D) fill_text(text string, x f64, y f64, max_width f64) {
if max_width == -1.0 {
#ctx.ctx.fillText(text.str,x.val,y.val,max_width.val)
} else {
#ctx.ctx.fillText(text.str,x.val,y.val)
}
}
/// stoke_text strokes — that is, draws the outlines of — the characters of a text string at the specified coordinates.
/// `max_width` allows specifying a maximum width for the rendered text, set max_width to -1.0 to automatically adjust text width.
pub fn (ctx CanvasRenderingContext2D) stroke_text(text string, x f64, y f64, max_width f64) {
if max_width == -1.0 {
#ctx.ctx.stokeText(text.str,x.val,y.val,max_width.val)
} else {
#ctx.ctx.stokeText(text.str,x.val,y.val)
}
}
pub fn (ctx CanvasRenderingContext2D) measure_text(text string) TextMetrics {
metrics := TextMetrics{}
#let tmp = ctx.ctx.measureText(text.str);
#metrics.width = new f64(tmp.width);
#metrics.actual_bounding_box_left = new f64(tmp.actualBoundingBoxLeft);
#metrics.actual_bounding_box_right = new f64(tmp.actualBoundingBoxRight);
#metrics.actual_bounding_box_ascent = new f64(tmp.actualBoundingBoxAscent);
#metrics.actual_bounding_box_descent = new f64(tmp.actualBoundingBoxDescent);
#metrics.font_bounding_box_ascent = new f64(tmp.fontBoundingBoxAscent);
#metrics.font_bounding_box_descent = new f64(tmp.fontBoundingBoxDescent);
#metrics.em_height_ascent = new f64(tmp.emHeightAscent);
#metrics.em_height_descent = new f64(tmp.emHeightDescent);
#metrics.hanging_baseline = new f64(tmp.hangingBaseline);
#metrics.alphabetic_baseline = new f64(tmp.alphabeticBaseline);
#metrics.ideographic_baseline = new f64(tmp.ideographicBaseline);
return metrics
}
pub fn (ctx CanvasRenderingContext2D) fill_path(p Path2D) {
#ctx.ctx.fill(p.path);
}
pub enum FillRule {
nonzero
evenodd
}
pub fn (ctx CanvasRenderingContext2D) clip_rule(rule FillRule) {
match rule {
.nonzero {
#ctx.ctx.clip('nonzero')
}
.evenodd {
#ctx.ctx.clip('evenodd')
}
}
}
pub fn (ctx CanvasRenderingContext2D) clip() {
#ctx.ctx.clip();
}
pub fn (ctx CanvasRenderingContext2D) clip_path(path Path2D) {
#ctx.ctx.clip(path.path);
}
pub fn (ctx CanvasRenderingContext2D) clip_path_rule(path Path2D, rule FillRule) {
match rule {
.nonzero {
#ctx.ctx.clip(path.path, 'nonzero')
}
.evenodd {
#ctx.ctx.clip(path.path,'evenodd')
}
}
}
pub fn (ctx CanvasRenderingContext2D) is_point_in_path(x f64, y f64) bool {
res := false
#res.val = ctx.ctx.isPointInPath(x.val,y.val);
return res
}
pub fn (ctx CanvasRenderingContext2D) is_point_in_path_2(path Path2D, x f64, y f64) bool {
res := false
#res.val = ctx.ctx.isPointInPath(path.path,x.val,y.val);
return res
}
pub fn (ctx CanvasRenderingContext2D) is_point_in_path_3(path Path2D, x f64, y f64, rule FillRule) bool {
res := false
match rule {
.nonzero {
#res.val = ctx.ctx.isPointInPath(path.path,x.val,y.val,'nonzero');
}
.evenodd {
#res.val = ctx.ctx.isPointInPath(path.path,x.val,y.val,'evenadd');
}
}
return res
}
pub fn (ctx CanvasRenderingContext2D) is_point_in_path_4(x f64, y f64, rule FillRule) bool {
res := false
match rule {
.nonzero {
#res.val = ctx.ctx.isPointInPath(x.val,y.val,'nonzero');
}
.evenodd {
#res.val = ctx.ctx.isPointInPath(x.val,y.val,'evenadd');
}
}
return res
}
pub fn (ctx CanvasRenderingContext2D) is_point_in_stroke(x f64, y f64) bool {
res := false
#res.val = ctx.ctx.isPointInStroke(x.val,y.val);
return res
}
pub fn (ctx CanvasRenderingContext2D) is_point_in_stroke_path(path Path2D, x f64, y f64) bool {
res := false
#res.val = ctx.ctx.isPointInStroke(path.path, x.val,y.val);
return res
}
pub fn (ctx CanvasRenderingContext2D) get_transform() DOMMatrix {
m := DOMMatrix{}
#m.matrix = ctx.ctx.getTransform();
return m
}
pub fn (ctx CanvasRenderingContext2D) rotate(angle f64) {
#ctx.ctx.rotate(angle.val);
}
pub fn (ctx CanvasRenderingContext2D) scale(x f64, y f64) {
#ctx.ctx.scale(x.val,y.val);
}
pub fn (ctx CanvasRenderingContext2D) translate(x f64, y f64) {
#ctx.ctx.translate(x.val,y.val)
}
pub fn (ctx CanvasRenderingContext2D) transform(a f64, b f64, c f64, d f64, e f64, f f64) {
#ctx.ctx.transform(a.val,b.val,c.val,d.val,e.val,f.val);
}
pub fn (ctx CanvasRenderingContext2D) set_transform_matrix(m DOMMatrix) {
#ctx.ctx.setTransform(m.matrix);
}
pub fn (ctx CanvasRenderingContext2D) set_transform(a f64, b f64, c f64, d f64, e f64, f f64) {
#ctx.ctx.setTransform(a.val,b.val,c.val,d.val,e.val,f.val);
}
pub fn (ctx CanvasRenderingContext2D) global_alpha() f64 {
res := 0.0
#res.val = ctx.ctx.globalAlpha
return res
}
pub fn (ctx CanvasRenderingContext2D) set_global_alpha(alpha f64) {
#ctx.ctx.globalAlpha = alpha.val;
}
pub fn (ctx CanvasRenderingContext2D) global_composite_operation() string {
res := ''
#res.str = ctx.ctx.globalCompositeOperation
return res
}
pub fn (ctx CanvasRenderingContext2D) set_global_composite_operation(typ string) {
#ctx.ctx.globalCompositeOperation = typ.str;
}
pub fn (ctx CanvasRenderingContext2D) save() {
#ctx.ctx.save();
}
pub fn (ctx CanvasRenderingContext2D) restore() {
#ctx.ctx.restore()
}
pub fn (ctx CanvasRenderingContext2D) canvas() HTMLCanvasElement {
elem := HTMLCanvasElement{}
#elem.node = ctx.ctx.canvas()
return elem
}

View File

@ -1,230 +0,0 @@
module jsdom
pub struct JS.Document {
}
pub struct Document {
Node
}
pub struct Location {
mut:
loc JS.Location [noinit]
}
pub fn (l Location) str() string {
mut res := 'Location{\n'
res += ' origin: $l.origin()\n'
res += ' href: $l.href()\n'
res += ' protocol: $l.protocol()\n'
res += ' host: $l.host()\n'
res += ' hostname: $l.hostname()\n'
res += ' port: $l.port()\n'
res += ' pathname: $l.pathname()\n'
res += ' search: $l.search()\n'
res += ' hash: $l.hash()\n'
return res
}
pub fn (mut l Location) assign(url string) {
#l.val.loc.assign(url.str)
}
pub fn (l Location) reload() {
#l.loc.reload()
}
pub fn (mut l Location) replace(url string) {
#l.val.loc.replace(url.str)
}
pub fn (l Location) origin() string {
return tos(l.loc.origin)
}
pub fn (l Location) href() string {
return tos(l.loc.href)
}
pub fn (mut l Location) set_href(href string) {
l.loc.href = href.str
}
pub fn (l Location) protocol() string {
return tos(l.loc.protocol)
}
pub fn (mut l Location) set_protocol(protocol string) {
l.loc.protocol = protocol.str
}
pub fn (l Location) host() string {
return tos(l.loc.host)
}
pub fn (mut l Location) set_host(host string) {
l.loc.host = host.str
}
pub fn (l Location) hostname() string {
return tos(l.loc.hostname)
}
pub fn (mut l Location) set_hostname(hostname string) {
l.loc.hostname = hostname.str
}
pub fn (l Location) port() string {
return tos(l.loc.port)
}
pub fn (mut l Location) set_port(port string) {
l.loc.port = port.str
}
pub fn (l Location) pathname() string {
return tos(l.loc.pathname)
}
pub fn (mut l Location) set_pathname(pathname string) {
l.loc.pathname = pathname.str
}
pub fn (l Location) hash() string {
return tos(l.loc.hash)
}
pub fn (mut l Location) set_hash(hash string) {
l.loc.hash = hash.str
}
pub fn (l Location) search() string {
return tos(l.loc.search)
}
pub fn (mut l Location) set_search(search string) {
l.loc.search = search.str
}
pub struct JS.Location {
pub:
origin JS.String
mut:
href JS.String
protocol JS.String
host JS.String
hostname JS.String
port JS.String
pathname JS.String
search JS.String
hash JS.String
}
pub fn (doc Document) active_element() Element {
mut elem := Element{}
#elem.node = doc.node.activeElement;
return elem
}
pub fn (doc Document) get(name string) ?Element {
mut elem := Element{}
#elem.node = doc.node[name.str];
#console.log(elem.node)
#if (elem.node === null || elem.node === undefined) return new $ref(new Option({state: new byte(2),err: none__}));
return elem
}
// location returns URI of the document
pub fn (doc Document) location() Location {
mut loc := Location{}
#loc.loc = doc.node.location;
return loc
}
// get_title returns current title of document
pub fn (doc Document) get_title() string {
res := ''
#res.str = doc.node.title;
return res
}
// set_title updates document title
pub fn (doc Document) set_title(title string) {
#doc.node.title = title.str;
}
// url returns document location as a string
pub fn (doc Document) url() string {
res := ''
#res.str = doc.node.URL;
return res
}
// node casts `Document` back to `Node`.
pub fn (doc Document) node() Node {
node := Node{}
#node.node = doc.node
return node
}
pub fn (doc Document) get_element_by_id(id string) ?IElement {
mut elem := IElement(Element{})
found := false
#let tmp = doc.node.getElementById(id.str);
#elem = jsdom__dispatch_event_target(tmp);
#found.val = !(elem.node == null)
if !found {
return none
}
return elem
}
pub type DocumentPrepend = Node | string
pub fn (doc Document) prepend(nodes_or_strings ...DocumentPrepend) ? {
caught := false
err := ''
#try {
for elem in nodes_or_strings {
match elem {
string {
#doc.node.prepend(elem.str)
}
Node {
#doc.node.prepend(elem.node)
}
}
}
#} catch (e) { caught.val = true; err.str = e.toString(); }
if caught {
return error(err)
}
}
pub fn (doc Document) create_element(tag_name string) Element {
elem := Element{}
#elem.node = doc.node.createElement(tag_name.str)
return elem
}
pub fn get_document() Document {
doc := Document{}
#doc.node = document;
return doc
}
pub fn (elem Document) add_event_listener(event string, cb EventCallback) {
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
#let ev = jsdom__dispatch_event(event); ev.event = event;
#return cb(e,ev)
#});
}

View File

@ -1,202 +0,0 @@
// DOM API for JS backend
module jsdom
[heap]
pub struct JS.Node {
baseURI JS.String [noinit]
childNodes JS.NodeList [noinit]
firstChild voidptr [noinit]
isConnected JS.bool [noinit]
lastChild voidptr [noinit]
nextSibling voidptr [noinit]
nodeName JS.String [noinit]
nodeType NodeType [noinit]
nodeValue voidptr [noinit]
ownerDocument JS.Document [noinit]
parentNode voidptr [noinit]
parentElement JS.Element [noinit]
previousSibling voidptr [noinit]
textContext voidptr
}
pub struct JS.NodeList {
pub mut:
length JS.Number
}
pub enum NodeType {
element = 1
attribute = 2
text = 3
cdata_section = 4
entity_reference = 5
entity = 6
processing_instruction = 7
comment = 8
document = 9
document_type = 10
document_fragment = 11
notation = 12
}
pub struct Node {
node JS.Node [noinit]
}
pub fn (n Node) typ() NodeType {
return n.node.nodeType
}
/// IEventTarget interface is implemented by objects that can receive events and may have listeners for them.
// In other words, any target of events implements the three methods associated with this interface.
// TODO: remove_event_listener and dispatch_event
pub interface IEventTarget {
add_event_listener(event string, cb EventCallback)
}
/// The DOM Node interface is an abstract base class upon which many other DOM API objects are based, thus
// letting those object types to be used similarly and often interchangeably. As an abstract class,
// there is no such thing as a plain Node object. All objects that implement Node functionality are based on one of its subclasses.
// Most notable are Document, Element, and DocumentFragment.
pub interface INode {
IEventTarget
typ() NodeType
}
pub fn (elem Node) add_event_listener(event string, cb EventCallback) {
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
#let ev = jsdom__dispatch_event(event); ev.event = event;
#return cb(e,ev)
#});
}
pub fn (n INode) is_(ty NodeType) bool {
res := false
#res.val = n.node.nodeType == ty
return res
}
pub fn (n INode) document() ?Document {
res := Document{}
if n.is_(.document) {
#res.node = n.node
return res
} else {
return none
}
}
pub fn (n INode) element() ?Element {
res := Element{}
if n.is_(.element) {
#res.node = n.node
return res
} else {
return none
}
}
pub fn (n INode) append_child(child INode) {
#n.node.appendChild(child.node)
}
pub fn (n INode) clone_node(deep ...int) INode {
cloned := Node{}
if deep.len == 0 {
#cloned.node = n.node.cloneNode()
} else {
#cloned.node = n.node.cloneNode(deep.arr.get(new int(0)).val)
}
return cloned
}
pub fn (n INode) contains(other INode) bool {
res := false
#res.val = n.node.contains(other.node)
return res
}
pub fn (n INode) get_root_node() INode {
root := Node{}
#root.node = n.node.getRootNode()
return root
}
pub fn (n INode) has_child_nodes() bool {
res := false
#res.val = n.node.hasChildNodes()
return res
}
pub fn (n INode) insert_before(new_node INode, reference_node INode) Node {
inserted := Node{}
#inserted.node = n.node.insertBefore(new_node.node,reference_node.node)
return inserted
}
/*
pub fn (x Node) == (y Node) bool {
res := false
#res.val = x.node.isEqualNode(y.node)
return res
}*/
pub fn (n INode) remove_child(child INode) {
#n.node.removeChild(child.node)
}
pub fn (n INode) replace_child(new_child INode, old_child INode) INode {
#old_child.node = n.node.replace_child(new_child.node,old_child.node)
return old_child
}
pub struct JS.EventTarget {}
fn dispatch_event_target(target JS.EventTarget) IEventTarget {
mut ret := IEventTarget(Element{})
#if (target instanceof HTMLCanvasElement) { ret = new jsdom__HTMLCanvasElement({}); ret.node = target; }
#else if (target instanceof HTMLElement) { ret = new jsdom__HTMLElement({}); ret.node = target; }
#else if (target instanceof Window) { ret = new jsdom__Window({}); ret.node = target;}
#else if (target instanceof SVGElement) { ret = new jsdom__SVGElement({}); ret.node = target; }
#else if (target instanceof Element) { ret = new jsdom__Element({}); ret.node = target; }
#else if (target instanceof Document) { ret = new jsdom__Document({}); ret.node = target; }
return ret
}
pub type EventCallback = fn (_ IEventTarget, _ IEvent)
pub const (
document = Document{}
window = Window{}
)
fn init() {
#jsdom__document.node = document;
#jsdom__window.node = window;
}
pub struct TextMetrics {
pub:
width f64
actual_bounding_box_left f64
actual_bounding_box_right f64
font_bounding_box_ascent f64
font_bounding_box_descent f64
actual_bounding_box_ascent f64
actual_bounding_box_descent f64
em_height_ascent f64
em_height_descent f64
hanging_baseline f64
alphabetic_baseline f64
ideographic_baseline f64
}

View File

@ -1,10 +0,0 @@
// DOM API wrapper for JS backend
module jsdom
pub fn get_html_canvas_element(elem IElement) ?HTMLCanvasElement {
if elem is HTMLCanvasElement {
return *elem
} else {
return none
}
}

View File

@ -1,97 +0,0 @@
module jsdom
pub struct JS.DOMString {
}
pub struct JS.DOMTokenList {
length JS.Number
value JS.DOMString
}
pub struct DOMTokenList {
list JS.DOMTokenList [noinit]
}
pub fn (x DOMTokenList) len() int {
res := 0
#res.val = x.list.length;
return res
}
pub fn (x DOMTokenList) item(idx int) ?string {
res := ''
#let tmp = x.list.item(idx.list.val)
#if (tmp === undefined) return new Option({state: new byte(2),err: none__});
#res.val = tmp
return res
}
pub fn (x DOMTokenList) contains(token string) bool {
res := false
#res.val = x.list.contains(token.str);
return res
}
pub fn (x DOMTokenList) add(tokens ...string) {
for token in tokens {
#x.list.add(token.str);
_ := token
}
}
pub fn (x DOMTokenList) remove(tokens ...string) {
for token in tokens {
#x.list.remove(token.str);
_ := token
}
}
pub fn (x DOMTokenList) replace(old_token string, new_token string) bool {
is_replaced := false
#is_replaced.val = x.list.replace(old_token.str,new_token.str);
return is_replaced
}
// supports returns true if the given `token` is in the associated attibute's supported tokens.
pub fn (x DOMTokenList) supports(token string) bool {
supports := false
#supports.val = x.list.supports(token.str)
return supports
}
// toggle removes a given token from the list and returns `false`. If token does not exist
// it is added and function returns `true`.
pub fn (x DOMTokenList) toggle(token string, force bool) bool {
res := false
#res.val = x.list.toggle(token.str, force.val);
return res
}
// entries returns array of all tokens in this token list
pub fn (x DOMTokenList) values() []string {
mut res := []string{}
#for (let [_,value] of x.list.entries()) array_push(res, new string(value));
return res
}
pub fn (x DOMTokenList) str() string {
mut fmt := 'DOMTokenList['
values := x.values()
for i, val in values {
fmt += '"' + val + '"'
if i != values.len - 1 {
fmt += ','
}
}
fmt += ']'
return fmt
}

View File

@ -1,93 +0,0 @@
module jsdom
pub struct JS.Element {
classList JS.DOMTokenList
childElementCount JS.Number
className JS.String
clientHeight JS.Number
clientWidth JS.Number
clientTop JS.Number
clientLeft JS.Number
id JS.String
innerHTML JS.String
namespaceURI JS.String
outerHTML JS.String
scrollHeight JS.Number
scrollLeft JS.Number
scrollTop JS.Number
scrollWidth JS.Number
}
pub struct Element {
Node
}
pub fn (e Element) str() string {
res := ''
#res.str = e.node + ''
return res
}
pub fn (elem Element) typ() NodeType {
return .element
}
pub fn (e Element) class_name() string {
res := ''
#res.str = e.node.className
return res
}
pub fn (e Element) class_list() DOMTokenList {
list := DOMTokenList{}
#list.list = e.node.classList
return list
}
// node casts `Element` back to `Node`.
pub fn (elem Element) node() Node {
node := Node{}
#node.node = elem.node
return node
}
pub fn (elem Element) add_event_listener(event string, cb EventCallback) {
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
#let ev = jsdom__dispatch_event(event); ev.event = event;
#return cb(e,ev)
#});
}
pub interface IElement {
INode
}
pub struct HTMLElement {
Element
}
pub fn (elem HTMLElement) typ() NodeType {
return .element
}
pub fn (elem HTMLElement) access_key() string {
res := ''
#res.str = elem.node.accessKey;
return res
}
pub fn (mut elem HTMLElement) set_access_key(key string) {
#elem.val.node.accessKey = key.str;
}
pub fn (elem HTMLElement) add_event_listener(event string, cb EventCallback) {
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
#let ev = jsdom__dispatch_event(event); ev.event = event;
#return cb(e,ev)
#});
}

View File

@ -1,164 +0,0 @@
module jsdom
pub interface IEvent {
composed_path() []IEventTarget
}
pub struct JS.Event {}
pub struct JS.MouseEvent {}
pub struct Event {
event JS.Event [noinit]
}
pub fn (ev Event) composed_path() []IEventTarget {
mut composed := []IEventTarget{}
#ev.event.composedPath().forEach((item) => {
#array_push(composed, jsdom__dispatch_event())
#})
return composed
}
pub struct UIEvent {
Event
}
// detail returns `int` with detail about the event, depending on the event type.
pub fn (ev UIEvent) detail() int {
ret := 0
#ret.val = ev.event.detail
return ret
}
pub struct MouseEvent {
UIEvent
}
// button returns the button number that was pressed (if applicable) when the mouse event was fired.
pub fn (ev MouseEvent) button() int {
ret := 0
#ret.val = ev.event.button;
return ret
}
// alt_key returns `true` if the `alt` key was down when the mouse event was fired.
pub fn (ev MouseEvent) alt_key() bool {
ret := false
#ret.val = ev.event.altKey;
return ret
}
// buttons returns the buttons being depressed (if any) when the mouse event was fired.
pub fn (ev MouseEvent) buttons() int {
ret := 0
#ret.val = ev.event.buttons;
return ret
}
// client_x returns the X coordinate of the mouse pointer in local coordinates.
pub fn (ev MouseEvent) client_x() int {
ret := 0
#ret.val = ev.event.clientX;
return ret
}
// client_y returns the Y coordinate of the mouse pointer in local coordinates.
pub fn (ev MouseEvent) client_y() int {
ret := 0
#ret.val = ev.event.clientY;
return ret
}
// ctrl_key returns `true` if the `ctrl` key was down when the mouse event was fired.
pub fn (ev MouseEvent) ctrl_key() bool {
ret := false
#ret.val = ev.event.ctrlKey;
return ret
}
// meta_key returns `true` if the `meta` key was down when the mouse event was fired.
pub fn (ev MouseEvent) meta_key() bool {
ret := false
#ret.val = ev.event.metaKey;
return ret
}
// movenet_x reaturns the X coordinate of the mouse pointer relative to the position of the last `mousemove` event.
pub fn (ev MouseEvent) movement_x() int {
ret := 0
#ret.val = ev.event.movementX;
return ret
}
// movenet_y reaturns the Y coordinate of the mouse pointer relative to the position of the last `mousemove` event.
pub fn (ev MouseEvent) movement_y() int {
ret := 0
#ret.val = ev.event.movementY;
return ret
}
// offset_x returns the X coordinate of the mouse pointer relative to the position of the padding edge of the target node.
pub fn (ev MouseEvent) offset_x() int {
ret := 0
#ret.val = ev.event.offsetX;
return ret
}
// offset_y reaturns the Y coordinate of the mouse pointer relative to the position of the padding edge of the target node.
pub fn (ev MouseEvent) offset_y() int {
ret := 0
#ret.val = ev.event.offsetY;
return ret
}
pub fn (ev MouseEvent) composed_path() []IEventTarget {
mut composed := []IEventTarget{}
#ev.event.composedPath().forEach((item) => {
#array_push(composed, jsdom__dispatch_event())
#})
return composed
}
pub struct AbortSignal {
Event
}
pub fn (ev AbortSignal) composed_path() []IEventTarget {
mut composed := []IEventTarget{}
#ev.event.composedPath().forEach((item) => {
#array_push(composed, jsdom__dispatch_event(item))
#})
return composed
}
pub fn (sig AbortSignal) aborted() bool {
res := false
#res.val = sig.event.aborted;
return res
}
fn dispatch_event(event JS.Event) IEvent {
mut ret := IEvent(Event{})
#if (event instanceof AbortSignal) { ret = new jsdom__AbortSignal({}); }
#else if (event instanceof MouseEvent) { ret = new jsdom__MouseEvent({}); }
#ret.event = event
return ret
}

View File

@ -1,47 +0,0 @@
module jsdom
pub struct HTMLCanvasElement {
HTMLElement
}
pub fn (cv HTMLCanvasElement) height() int {
ret := 0
#ret.val = cv.node.height;
return ret
}
pub fn (cv HTMLCanvasElement) width() int {
ret := 0
#ret.val = cv.node.width;
return ret
}
pub fn (cv HTMLCanvasElement) typ() NodeType {
return .element
}
pub fn (elem HTMLCanvasElement) add_event_listener(event string, cb EventCallback) {
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
#let ev = jsdom__dispatch_event(event); ev.event = event;
#return cb(e,ev)
#});
}
pub fn (elem HTMLCanvasElement) get_context(ctx_ string) ContextResult {
mut res := NoneContext{}
#let ctx = elem.node.getContext(ctx_.str);
#if (ctx instanceof CanvasRenderingContext2D) { res = new jsdom__CanvasRenderingContext2D(ctx); res.ctx = ctx; }
return res
}
pub fn (elem HTMLCanvasElement) get_context_2d() CanvasRenderingContext2D {
mut res := CanvasRenderingContext2D{}
#let ctx = elem.node.getContext('2d');
#res = new jsdom__CanvasRenderingContext2D(ctx);
#res.ctx = ctx;
return res
}

View File

@ -0,0 +1,138 @@
module jsdom
pub struct CanvasRenderingContext2DSettings {
pub mut:
alpha bool
color_space string
desynchronized bool
will_read_frequently bool
}
pub interface JS.DOMMatrix2DInit {
mut:
a JS.Number
b JS.Number
c JS.Number
d JS.Number
e JS.Number
f JS.Number
m11 JS.Number
m12 JS.Number
m21 JS.Number
m22 JS.Number
m41 JS.Number
m42 JS.Number
}
pub interface JS.DOMMatrixInit {
JS.DOMMatrix2DInit
is2D JS.Boolean
mut:
m13 JS.Number
m14 JS.Number
m23 JS.Number
m24 JS.Number
m31 JS.Number
m32 JS.Number
m33 JS.Number
m34 JS.Number
m43 JS.Number
m44 JS.Number
}
pub interface JS.DOMMatrix {
is2D JS.Boolean
isIdentity JS.Boolean
flipX() JS.DOMMatrix
flipY() JS.DOMMatrix
inverse() JS.DOMMatrix
multiply(other JS.DOMMatrix) JS.DOMMatrix
rotate(rotX JS.Number, rotY JS.Number, rotZ JS.Number) JS.DOMMatrix
rotateAxisAngle(x JS.Number, y JS.Number, z JS.Number, angle JS.Number) JS.DOMMatrix
scale(scaleX JS.Number, scaleY JS.Number, scaleZ JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
scale3d(scale JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
skewX(sx JS.Number) JS.DOMMatrix
skewY(sy JS.Number) JS.DOMMatrix
translate(tx JS.Number, ty JS.Number, tz JS.Number) JS.DOMMatrix
invertSelf() JS.DOMMatrix
multiplySelf(other JS.DOMMatrix) JS.DOMMatrix
preMultiplySelf(other JS.DOMMatrix) JS.DOMMatrix
rotateAxisAngleSelf(x JS.Number, y JS.Number, z JS.Number, angle JS.Number) JS.DOMMatrix
rotateFromVectorSelf(x JS.Number, y JS.Number) JS.DOMMatrix
rotateSelf(rotX JS.Number, rotY JS.Number, rotZ JS.Number) JS.DOMMatrix
scale3dSelf(scale JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
scaleSelf(scaleX JS.Number, scaleY JS.Number, scaleZ JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
toString() JS.String
mut:
a JS.Number
b JS.Number
c JS.Number
d JS.Number
e JS.Number
f JS.Number
m11 JS.Number
m12 JS.Number
m13 JS.Number
m14 JS.Number
m21 JS.Number
m22 JS.Number
m23 JS.Number
m24 JS.Number
m31 JS.Number
m32 JS.Number
m33 JS.Number
m34 JS.Number
m41 JS.Number
m42 JS.Number
m43 JS.Number
m44 JS.Number
}
pub type SVGMatrix = JS.DOMMatrix
pub type WebKitCSSMatrix = JS.DOMMatrix
[use_new]
pub fn JS.DOMMatrix.prototype.constructor(init JS.Array) JS.DOMMatrix
pub interface JS.DOMPoint {
matrixTransform(matrix JS.DOMMatrix) JS.DOMPoint
mut:
w JS.Number
x JS.Number
y JS.Number
z JS.Number
}
[use_new]
pub fn JS.DOMPoint.prototype.constructor(x JS.Number, y JS.Number, z JS.Number, w JS.Number) JS.DOMPoint
pub interface JS.DOMQuad {
p1 JS.DOMPoint
p2 JS.DOMPoint
p3 JS.DOMPoint
p4 JS.DOMPoint
getBounds() JS.DOMRect
}
[use_new]
pub fn JS.DOMQuad.prototype.constructor(p1 JS.DOMPoint, p2 JS.DOMPoint, p3 JS.DOMPoint, p4 JS.DOMPoint) JS.DOMQuad
pub fn JS.DOMQuad.fromQuad(other JS.DOMQuad) JS.DOMQuad
pub fn JS.DOMQuad.fromRect(other JS.DOMRect) JS.DOMRect
pub interface JS.DOMRect {
bottom JS.Number
left JS.Number
right JS.Number
top JS.Number
mut:
height JS.Number
width JS.Number
x JS.Number
y JS.Number
}
pub interface JS.DOMStringList {
length JS.Number
contains(JS.String) JS.Boolean
item(index JS.Number) ?JS.String
}

View File

@ -0,0 +1,2 @@
// DOM API wrapper
module jsdom

View File

@ -1,365 +0,0 @@
module jsdom
pub interface JS.DOMMatrix {
is_2d JS.Boolean
is_identity JS.Boolean
mut:
m11 JS.Number
m12 JS.Number
m13 JS.Number
m14 JS.Number
m21 JS.Number
m22 JS.Number
m23 JS.Number
m24 JS.Number
m31 JS.Number
m32 JS.Number
m33 JS.Number
m34 JS.Number
m41 JS.Number
m42 JS.Number
m43 JS.Number
m44 JS.Number
a JS.Number
b JS.Number
c JS.Number
d JS.Number
e JS.Number
f JS.Number
}
pub struct DOMMatrix {
mut:
matrix JS.DOMMatrix = JS.DOMMatrix(voidptr(0))
}
pub fn (matrix DOMMatrix) str() string {
fmt := ''
#fmt.str = matrix.matrix + ''
return fmt
}
pub fn new_matrix(init []f64) DOMMatrix {
#let tmp = new Array();
for val in init {
_ := val
#tmp.push(val);
}
mut m := JS.DOMMatrix(voidptr(0))
#m = new DOMMatrix(tmp);
return DOMMatrix{m}
}
pub fn (m DOMMatrix) invert_self() {
#m.matrix.invertSelf();
}
pub fn (m DOMMatrix) multiply_self(other DOMMatrix) {
#m.matrix.multiplySelf(other.matrix);
}
pub fn (m DOMMatrix) pre_multiply_self(other DOMMatrix) {
#m.matrix.preMultiplySelf(other.matrix);
}
pub fn (m DOMMatrix) translate_self(tx f64, ty f64, tz f64) {
#m.matrix.translateSelf(tx.val,ty.val,tz.val);
}
pub fn (m DOMMatrix) scale3d_self(scale f64, origin_x f64, origin_y f64, origin_z f64) {
#m.matrix.scale3dSelf(scale.val,origin_x.val,origin_y.val,origin_z.val)
}
pub fn (m DOMMatrix) scale_self(scale_x f64, scale_y f64, scale_z f64, origin_x f64, origin_y f64, origin_z f64) {
#m.matrix.scaleSelf(scale_x.val,scale_y.val,scale_z.val,origin_x.val,origin_y.val,origin_z.val);
}
pub fn (m DOMMatrix) rotate_self(rot_x f64, rot_y f64, rot_z f64) {
#m.matrix.rotateSelf(rot_x.val,rot_y.val,rot_z.val);
}
pub fn (m DOMMatrix) rotate_axis_angle_self(x f64, y f64, z f64, angle f64) {
#m.matrix.rotateAxisAngleSelf(x.val,y.val,z.val,angle.val);
}
pub fn (m DOMMatrix) rotate_from_vector_self(x f64, y f64) {
#m.matrix.rotateFromVectorSelf(x.val,y.val);
}
pub fn (m DOMMatrix) skew_x_self(sx f64) {
#m.matrix.skewXSelf(sx.val);
}
pub fn (m DOMMatrix) skew_y_self(sy f64) {
#m.matrix.skewYSelf(sy.val);
}
pub fn (m DOMMatrix) flip_x() DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.flipX();
return res
}
pub fn (m DOMMatrix) flip_y() DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.flipY();
return res
}
pub fn (m DOMMatrix) inverse() DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.inverse();
return res
}
pub fn (m DOMMatrix) multiply(other DOMMatrix) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.multiply(other.matrix);
return res
}
pub fn (m DOMMatrix) rotate(rot_x f64, rot_y f64, rot_z f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.rotate(rot_x.val,rot_y.val,rot_z.val);
return res
}
pub fn (m DOMMatrix) rotate_axis_angle(x f64, y f64, z f64, angle f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.rotateAxisAngle(x.val,y.val,z.val,angle.val);
return res
}
pub fn (m DOMMatrix) rotate_from_vector(x f64, y f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.rotateFromVector(x.val,y.val);
return res
}
pub fn (m DOMMatrix) scale(scale_x f64, scale_y f64, scale_z f64, origin_x f64, origin_y f64, origin_z f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.scale(scale_x.val,scale_y.val,scale_z.val,origin_x.val,origin_y.val,origin_z.val);
return res
}
pub fn (m DOMMatrix) scale3d(scale f64, origin_x f64, origin_y f64, origin_z f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.scale3d(scale.val, origin_x.val,origin_y.val,origin_z.val);
return res
}
pub fn (m DOMMatrix) skew_x(sx f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.skewX(sx.val);
return res
}
pub fn (m DOMMatrix) skew_y(sy f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.skewY(sy.val);
return res
}
pub fn (m DOMMatrix) translate(tx f64, ty f64, tz f64) DOMMatrix {
res := DOMMatrix{}
#res.matrix = m.matrix.translate(tx.val,ty.val,tz.val);
return res
}
pub fn (m DOMMatrix) is_2d() bool {
res := false
#res.val = m.matrix.is2D.val;
return res
}
pub fn (m DOMMatrix) a() f64 {
return f64(m.matrix.a)
}
pub fn (m DOMMatrix) b() f64 {
return f64(m.matrix.b)
}
pub fn (m DOMMatrix) c() f64 {
return f64(m.matrix.c)
}
pub fn (m DOMMatrix) d() f64 {
return f64(m.matrix.d)
}
pub fn (m DOMMatrix) e() f64 {
return f64(m.matrix.e)
}
pub fn (m DOMMatrix) f() f64 {
return f64(m.matrix.f)
}
pub fn (mut m DOMMatrix) set_a(a f64) {
m.matrix.a = JS.Number(a)
}
pub fn (mut m DOMMatrix) set_b(b f64) {
m.matrix.b = JS.Number(b)
}
pub fn (mut m DOMMatrix) set_c(c f64) {
m.matrix.c = JS.Number(c)
}
pub fn (mut m DOMMatrix) set_d(d f64) {
m.matrix.d = JS.Number(d)
}
pub fn (mut m DOMMatrix) set_e(e f64) {
m.matrix.e = JS.Number(e)
}
pub fn (mut m DOMMatrix) set_f(f f64) {
m.matrix.f = JS.Number(f)
}
pub fn (m DOMMatrix) m11() f64 {
return f64(m.matrix.m11)
}
pub fn (m DOMMatrix) m12() f64 {
return f64(m.matrix.m12)
}
pub fn (m DOMMatrix) m13() f64 {
return f64(m.matrix.m13)
}
pub fn (m DOMMatrix) m14() f64 {
return f64(m.matrix.m14)
}
pub fn (m DOMMatrix) m21() f64 {
return f64(m.matrix.m21)
}
pub fn (m DOMMatrix) m22() f64 {
return f64(m.matrix.m22)
}
pub fn (m DOMMatrix) m23() f64 {
return f64(m.matrix.m23)
}
pub fn (m DOMMatrix) m24() f64 {
return f64(m.matrix.m24)
}
pub fn (m DOMMatrix) m31() f64 {
return f64(m.matrix.m31)
}
pub fn (m DOMMatrix) m32() f64 {
return f64(m.matrix.m32)
}
pub fn (m DOMMatrix) m33() f64 {
return f64(m.matrix.m33)
}
pub fn (m DOMMatrix) m34() f64 {
return f64(m.matrix.m34)
}
pub fn (m DOMMatrix) m41() f64 {
return f64(m.matrix.m41)
}
pub fn (m DOMMatrix) m42() f64 {
return f64(m.matrix.m42)
}
pub fn (m DOMMatrix) m43() f64 {
return f64(m.matrix.m43)
}
pub fn (m DOMMatrix) m44() f64 {
return f64(m.matrix.m44)
}
pub fn (mut m DOMMatrix) set_m11(x f64) {
m.matrix.m11 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m12(x f64) {
m.matrix.m12 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m13(x f64) {
m.matrix.m13 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m14(x f64) {
m.matrix.m14 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m21(x f64) {
m.matrix.m21 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m22(x f64) {
m.matrix.m22 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m23(x f64) {
m.matrix.m23 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m24(x f64) {
m.matrix.m24 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m31(x f64) {
m.matrix.m31 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m32(x f64) {
m.matrix.m32 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m33(x f64) {
m.matrix.m33 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m34(x f64) {
m.matrix.m34 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m41(x f64) {
m.matrix.m41 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m42(x f64) {
m.matrix.m42 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m43(x f64) {
m.matrix.m43 = JS.Number(x)
}
pub fn (mut m DOMMatrix) set_m44(x f64) {
m.matrix.m44 = JS.Number(x)
}

View File

@ -1,63 +0,0 @@
module jsdom
pub struct JS.Path2D {}
pub fn (p JS.Path2D) addPath(JS.Path2D, JS.DOMMatrix)
pub fn (p JS.Path2D) closePath()
pub fn (p JS.Path2D) moveTo(x JS.Number, y JS.Number)
pub fn (p JS.Path2D) lineTo(x JS.Number, y JS.Number)
pub fn (p JS.Path2D) bezierCurveTo(cp1x JS.Number, cp1y JS.Number, cp2x JS.Number, cp2y JS.Number, x JS.Number, y JS.Number)
pub fn (p JS.Path2D) quadraticCurveTo(cpx JS.Number, cpy JS.Number, x JS.Number, y JS.Number)
pub fn (p JS.Path2D) arc(x JS.Number, y JS.Number, radius JS.Number, startAngle JS.Number, endAngle JS.Number, counter_clockwise JS.Boolean)
pub fn (p JS.Path2D) arcTo(x1 JS.Number, y1 JS.Number, x2 JS.Number, y2 JS.Number, radius JS.Number)
pub fn (p JS.Path2D) ellipse(x JS.Number, y JS.Number, radius_x JS.Number, radius_y JS.Number, rotation JS.Number, start_angle JS.Number, end_angle JS.Number, counter_clockwise JS.Boolean)
pub fn (p JS.Path2D) rect(x JS.Number, y JS.Number, width JS.Number, height JS.Number)
pub struct Path2D {
mut:
path JS.Path2D [noinit]
}
pub fn (p Path2D) add_path(p2 Path2D) {
#p.path.addPath(p2.path);
}
pub fn (p Path2D) add_path_with_transform(p2 Path2D, m DOMMatrix) {
p.path.addPath(p2.path, m.matrix)
}
pub fn (path Path2D) bezier_curve_to(cp1x f64, cp1y f64, cp2x f64, cp2y f64, x f64, y f64) {
#path.path.bezierCurveTo(cp1x.val,cp1y.val,cp2x.val,cp2y.val, x.val,y.val);
}
pub fn (path Path2D) quadratic_curve_to(cpx f64, cpy f64, x f64, y f64) {
#path.path.quadraticCurveTo(cpx.val,cpy.val,x.val,y.val);
}
pub fn (path Path2D) arc(x f64, y f64, radius f64, start_angle f64, end_angle f64, counter_clockwise bool) {
#path.path.arc(x.val,y.val,radius.val,start_angle.val,end_angle.val,counter_clockwise.val)
}
pub fn (path Path2D) arc_to(x1 f64, y1 f64, x2 f64, y2 f64, radius f64) {
#path.path.arcTo(x1.val,y1.val,x2.val,y2.val,radius.val);
}
pub fn (path Path2D) ellipse(x f64, y f64, radius_x f64, radius_y f64, rotation f64, start_angle f64, end_angle f64, counter_clockwise bool) {
#path.path.ellipse(x.val,y.val,radius_x.val,radius_y.val,rotation.val,start_angle.val,end_angle.val,counter_clockwise.val);
}
pub fn (path Path2D) rect(x f64, y f64, width f64, height f64) {
#path.path.rect(x.val,y.val,widht.val,height.val);
}
pub fn (path Path2D) line_to(x f64, y f64) {
path.path.lineTo(JS.Number(x), JS.Number(y))
}
pub fn (path Path2D) move_to(x f64, y f64) {
path.path.lineTo(JS.Number(x), JS.Number(y))
}
pub fn (path Path2D) close_path() {
path.path.closePath()
}

View File

@ -1,71 +0,0 @@
module jsdom
pub struct JS.DOMPoint {
pub mut:
x JS.Number [noinit]
y JS.Number [noinit]
z JS.Number [noinit]
w JS.Number [noinit]
}
pub struct DOMPoint {
mut:
point JS.DOMPoint
}
pub fn new_dompoint(x f64, y f64, z f64, w f64) DOMPoint {
mut point := DOMPoint{}
point.point.x = JS.Number(x)
point.point.y = JS.Number(y)
point.point.z = JS.Number(z)
point.point.w = JS.Number(w)
return point
}
pub fn (p DOMPoint) x() f64 {
return f64(p.point.x)
}
pub fn (p DOMPoint) y() f64 {
return f64(p.point.y)
}
pub fn (p DOMPoint) z() f64 {
return f64(p.point.z)
}
pub fn (p DOMPoint) w() f64 {
return f64(p.point.w)
}
pub fn (mut p DOMPoint) set_x(x f64) {
p.point.x = JS.Number(x)
}
pub fn (mut p DOMPoint) set_y(y f64) {
p.point.y = JS.Number(y)
}
pub fn (mut p DOMPoint) set_z(z f64) {
p.point.z = JS.Number(z)
}
pub fn (mut p DOMPoint) set_w(w f64) {
p.point.w = JS.Number(w)
}
pub fn (p DOMPoint) matrix_transform(matrix DOMMatrix) DOMPoint {
mut point := DOMPoint{}
#point.point = p.point.matrixTransform(matrix.matrix);
return point
}
pub fn (p DOMPoint) matrix_transform_2() DOMPoint {
mut point := DOMPoint{}
#point.point = p.point.matrixTransform();
return point
}

View File

@ -1,3 +0,0 @@
module jsdom
pub struct WebGLRenderingContext {}

View File

@ -1,15 +0,0 @@
module jsdom
pub struct JS.Window {
}
pub struct Window {
node JS.Window [noinit]
}
pub fn (elem Window) add_event_listener(event string, cb EventCallback) {
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
#let ev = jsdom__dispatch_event(event); ev.event = event;
#return cb(e,ev)
#});
}

View File

@ -360,6 +360,7 @@ pub:
pos token.Position
pre_comments []Comment
generic_types []Type
attrs []Attr
pub mut:
methods []FnDecl
fields []StructField
@ -514,6 +515,7 @@ pub mut:
is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
is_keep_alive bool // GC must not free arguments before fn returns
is_noreturn bool // whether the function/method is marked as [noreturn]
is_ctor_new bool // if JS ctor calls requires `new` before call, marked as `[use_new]` in V
args []CallArg
expected_arg_types []Type
language Language

View File

@ -78,6 +78,7 @@ pub:
is_variadic bool
language Language
is_pub bool
is_ctor_new bool // `[use_new] fn JS.Array.prototype.constructor()`
is_deprecated bool // `[deprecated] fn abc(){}`
is_noreturn bool // `[noreturn] fn abc(){}`
is_unsafe bool // `[unsafe] fn abc(){}`
@ -1298,6 +1299,12 @@ pub fn (t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
return false
}
if mut inter_sym.info is Interface {
attrs := t.interfaces[inter_typ].attrs
for attr in attrs {
if attr.name == 'single_impl' {
return false
}
}
// do not check the same type more than once
for tt in inter_sym.info.types {
if tt.idx() == typ.idx() {

View File

@ -598,7 +598,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
c.error('field `$field.name` uses non JS type', field.pos)
}
}
if field.typ == node.typ {
if field.typ == node.typ && node.language != .js {
c.error('recursive interface fields are not allowed because they cannot be initialised',
field.type_pos)
}
@ -765,7 +765,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
c.error('cast to sum type using `${type_sym.name}($sexpr)` not `$type_sym.name{$sexpr}`',
node.pos)
}
if type_sym.kind == .interface_ {
if type_sym.kind == .interface_ && type_sym.language != .js {
c.error('cannot instantiate interface `$type_sym.name`', node.pos)
}
if type_sym.info is ast.Alias {
@ -2092,6 +2092,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
if has_method {
node.is_noreturn = method.is_noreturn
node.is_ctor_new = method.is_ctor_new
if !method.is_pub && !c.pref.is_test && method.mod != c.mod {
// If a private method is called outside of the module
// its receiver type is defined in, show an error.
@ -2696,6 +2697,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
}
node.is_noreturn = func.is_noreturn
node.is_ctor_new = func.is_ctor_new
if !found_in_args {
if node.scope.known_var(fn_name) {
c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`',

View File

@ -1063,6 +1063,7 @@ pub fn (mut f Fmt) hash_stmt(node ast.HashStmt) {
}
pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) {
f.attrs(node.attrs)
if node.is_pub {
f.write('pub ')
}

View File

@ -65,6 +65,15 @@ fn (mut g JsGen) js_mname(name_ string) string {
fn (mut g JsGen) js_call(node ast.CallExpr) {
g.call_stack << node
it := node
call_return_is_optional := it.return_type.has_flag(.optional)
if call_return_is_optional {
g.writeln('(function () {')
g.writeln('try {')
g.writeln('let tmp = ')
}
if it.is_ctor_new {
g.write('new ')
}
g.write('${g.js_mname(it.name)}(')
for i, arg in it.args {
g.expr(arg.expr)
@ -74,12 +83,51 @@ fn (mut g JsGen) js_call(node ast.CallExpr) {
}
// end call
g.write(')')
if call_return_is_optional {
g.write(';\n')
g.writeln('if (tmp === null || tmp === undefined) throw "none";')
g.writeln('return tmp;')
g.writeln('} catch(err) {')
g.inc_indent()
// gen or block contents
match it.or_block.kind {
.block {
if it.or_block.stmts.len > 1 {
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
}
// g.write('return ')
g.stmt(it.or_block.stmts.last())
}
.propagate {
panicstr := '`optional not set (\${err + ""})`'
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
g.writeln('return builtin__panic($panicstr)')
} else {
g.writeln('throw new Option({ state: new byte(2), err: error(new string($panicstr)) });')
}
}
else {}
}
// end catch
g.dec_indent()
g.writeln('}')
g.writeln('})()')
}
g.call_stack.delete_last()
}
fn (mut g JsGen) js_method_call(node ast.CallExpr) {
g.call_stack << node
it := node
call_return_is_optional := it.return_type.has_flag(.optional)
if call_return_is_optional {
g.writeln('(function () {')
g.writeln('try {')
g.writeln('let tmp = ')
}
if it.is_ctor_new {
g.write('new ')
}
g.expr(it.left)
g.write('.${g.js_mname(it.name)}(')
for i, arg in it.args {
@ -90,6 +138,36 @@ fn (mut g JsGen) js_method_call(node ast.CallExpr) {
}
// end method call
g.write(')')
if call_return_is_optional {
g.write(';\n')
g.writeln('if (tmp === null || tmp === undefined) throw "none";')
g.writeln('return tmp;')
g.writeln('} catch(err) {')
g.inc_indent()
// gen or block contents
match it.or_block.kind {
.block {
if it.or_block.stmts.len > 1 {
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
}
// g.write('return ')
g.stmt(it.or_block.stmts.last())
}
.propagate {
panicstr := '`optional not set (\${err + ""})`'
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
g.writeln('return builtin__panic($panicstr)')
} else {
g.writeln('throw new Option({ state: new byte(2), err: error(new string($panicstr)) });')
}
}
else {}
}
// end catch
g.dec_indent()
g.writeln('}')
g.writeln('})()')
}
g.call_stack.delete_last()
}

View File

@ -177,10 +177,14 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
iface := g.table.find_type(iface_name) or { panic('unreachable: interface must exist') }
for ty in iface_types {
sym := g.table.get_type_symbol(ty)
for method in iface.methods {
p_sym := g.table.get_type_symbol(ty)
mname := g.js_name(p_sym.name) + '_' + method.name
mname := if p_sym.has_method(method.name) {
g.js_name(p_sym.name) + '_' + method.name
} else {
g.js_name(iface_name) + '_' + method.name
}
g.write('${g.js_name(sym.name)}.prototype.$method.name = function(')
for i, param in method.params {
if i == 0 {
@ -3154,8 +3158,23 @@ fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
type_sym := g.table.get_type_symbol(it.typ)
name := type_sym.name
if it.fields.len == 0 {
if it.fields.len == 0 && type_sym.kind != .interface_ {
g.write('new ${g.js_name(name)}({})')
} 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
} else if type_sym.kind == .interface_ && it.fields.len != 0 {
g.writeln('(function () {')
g.inc_indent()
g.writeln('let tmp = new ${g.js_name(name)}()')
for field in it.fields {
g.write('tmp.$field.name = ')
g.expr(field.expr)
g.writeln(';')
}
g.writeln('return tmp')
g.dec_indent()
g.writeln('})()')
} else {
g.writeln('new ${g.js_name(name)}({')
g.inc_indent()

View File

@ -186,6 +186,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
mut is_unsafe := false
mut is_trusted := false
mut is_noreturn := false
mut is_ctor_new := false
mut is_c2v_variadic := false
for fna in p.attrs {
match fna.name {
@ -199,6 +200,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
'unsafe' { is_unsafe = true }
'trusted' { is_trusted = true }
'c2v_variadic' { is_c2v_variadic = true }
'use_new' { is_ctor_new = true }
else {}
}
}
@ -446,6 +448,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_pub: is_pub
is_deprecated: is_deprecated
is_noreturn: is_noreturn
is_ctor_new: is_ctor_new
is_unsafe: is_unsafe
is_main: is_main
is_test: is_test

View File

@ -431,6 +431,7 @@ fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
fn (mut p Parser) interface_decl() ast.InterfaceDecl {
p.top_level_statement_start()
mut pos := p.tok.position()
attrs := p.attrs
is_pub := p.tok.kind == .key_pub
if is_pub {
p.next()
@ -629,6 +630,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
methods: methods
ifaces: ifaces
is_pub: is_pub
attrs: attrs
pos: pos
pre_comments: pre_comments
generic_types: generic_types