ref: cdae93dae8b27ebf26cca981be01088e01e9f865
parent: 3ce4cfc9371c16b2ac4ac167668122fca13cc850
author: Philip Silva <philip.silva@protonmail.com>
date: Mon Dec 28 08:53:33 EST 2020
merge exec and export
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@
~*
.DS_Store
/cmd/browse/browse
+main.js
--- a/browser/experimental.go
+++ b/browser/experimental.go
@@ -3,7 +3,6 @@
import (
"fmt"
"image"
- "strings"
"opossum/domino"
"opossum/nodes"
"time"
@@ -137,42 +136,16 @@
})
}
-func processJS(htm string) (resHtm string, err error) {- _ = strings.Replace(htm, "window.", "", -1)
- d := domino.NewDomino(htm)
- d.Start()
- if err = d.ExecInlinedScripts(); err != nil {- return "", fmt.Errorf("exec <script>s: %w", err)- }
- time.Sleep(time.Second)
- resHtm, changed, err := d.TrackChanges()
- log.Infof("processJS: changes = %v", changed)- d.Stop()
- return
-}
-
func processJS2(d *domino.Domino, doc *nodes.Node, scripts []string) (resHtm string, err error) {- code := ""
+ initialized := false
for _, script := range scripts {- code += `
- try {- ` + script + `;
- ` + fmt.Sprintf(`
- console.log('==============');- console.log('Success!');- console.log('==============');- `) + `
- } catch(e) {- console.log('==============');- console.log('Catch:');- console.log(e);
- console.log('==============');- }
- `
+ if _, err := d.Exec/*6*/(script, !initialized); err == nil {+ initialized = true
+ } else {+ log.Errorf("exec <script>: %v", err)+ }
}
- if err = d.Exec/*6*/(code); err != nil {- return "", fmt.Errorf("exec <script>s: %w", err)- }
+
time.Sleep(time.Second)
resHtm, changed, err := d.TrackChanges()
if err != nil {--- a/domino/domino.go
+++ b/domino/domino.go
@@ -20,8 +20,8 @@
var DebugDumpJS *bool
type Domino struct {+ initialized bool
loop *eventloop.EventLoop
- vm *goja.Runtime
html string
outputHtml string
domChanged chan int
@@ -56,7 +56,6 @@
yx := strings.Split(yxStart, ":")
y, _ := strconv.Atoi(yx[0])
x, _ := strconv.Atoi(yx[1])
- log.Printf("line %v, column %v", y, x)lines := strings.Split(script, "\n")
if wholeLine := lines[y-1]; len(wholeLine) > 100 {@@ -81,18 +80,19 @@
}
}
-func (d *Domino) Exec(script string) (err error) {+func (d *Domino) Exec(script string, initial bool) (res string, err error) {+ if !initial && !d.initialized {+ initial = true
+ }
script = strings.Replace(script, "const ", "var ", -1)
script = strings.Replace(script, "let ", "var ", -1)
script = strings.Replace(script, "<!--", "", -1)
SCRIPT := `
- global = {};- //global.__domino_frozen__ = true; // Must precede any require('domino')- var domino = require('domino-lib/index');- var Element = domino.impl.Element; // etc
+ global = {};+ //global.__domino_frozen__ = true; // Must precede any require('domino')+ var domino = require('domino-lib/index');+ var Element = domino.impl.Element; // etc
- // JSDOM also knows the style tag
- // https://github.com/jsdom/jsdom/issues/2485
Object.assign(this, domino.createWindow(s.html, 'http://example.com'));
window = this;
window.parent = window;
@@ -102,54 +102,57 @@
window.location.href = 'http://example.com';
navigator = {};HTMLElement = domino.impl.HTMLElement;
- // Fire DOMContentLoaded
- // to trigger $(document)readfy!!!!!!!
- document.close();
+ // Fire DOMContentLoaded to trigger $(document).ready(..)
+ document.close();
` + script
+ if !initial {+ SCRIPT = script
+ }
if *DebugDumpJS { ioutil.WriteFile("main.js", []byte(SCRIPT), 0644)}
- ready := make(chan int)
+ ready := make(chan goja.Value)
go func() { d.loop.RunOnLoop(func(vm *goja.Runtime) { log.Printf("RunOnLoop")- registry := require.NewRegistry(
- require.WithGlobalFolders(".", ".."),- )
- console.Enable(vm)
- req := registry.Enable(vm)
- _ = req
+ if initial {+ registry := require.NewRegistry(
+ require.WithGlobalFolders(".", ".."),+ )
+ console.Enable(vm)
+ req := registry.Enable(vm)
+ _ = req
- vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))- type S struct {- Buf string `json:"buf"`
- HTML string `json:"html"`
- }
- d.vm = vm
+ vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))+ type S struct {+ Buf string `json:"buf"`
+ HTML string `json:"html"`
+ }
- vm.Set("s", S{- HTML: d.html,
- Buf: "yolo",
- })
- _, err := vm.RunString(SCRIPT)
+ vm.Set("s", S{+ HTML: d.html,
+ Buf: "yolo",
+ })
+ }
+ vv, err := vm.RunString(SCRIPT)
if err != nil { log.Printf("run program: %v", err)IntrospectError(err, script)
}
- ready <- 1
+ ready <- vv
})
}()
- <-ready
+ v := <-ready
<-time.After(10 * time.Millisecond)
- //res = fmt.Sprintf("%v", v.Export())- if _, _, err = d.TrackChanges(); err != nil {- return fmt.Errorf("track changes: %w", err)+ if v != nil {+ res = v.String()
}
+ if err == nil { d.initialized=true }return
}
-func (d *Domino) Exec6(script string) (err error) {+func (d *Domino) Exec6(script string) (res string, err error) {babel.Init(4) // Setup 4 transformers (can be any number > 0)
r, err := babel.Transform(strings.NewReader(script), map[string]interface{}{ "plugins": []string{@@ -158,67 +161,40 @@
},
})
if err != nil {- return fmt.Errorf("babel: %v", err)+ return "", fmt.Errorf("babel: %v", err)}
buf, err := ioutil.ReadAll(r)
if err != nil {- return fmt.Errorf("read all: %v", err)+ return "", fmt.Errorf("read all: %v", err)}
- return d.Exec(string(buf))
+ return d.Exec(string(buf), true)
}
-func (d *Domino) Export(expr string) (res string, err error) {- var v goja.Value
- ch := make(chan int, 1)
-
- d.loop.RunOnLoop(func(vm *goja.Runtime) {- v, err = vm.RunString(expr)
- ch <- 1
- })
-
- <-ch
-
- if err != nil {- return "", fmt.Errorf("export: %w", err)- }
- if v != nil {- res = fmt.Sprintf("%v", v.Export())- }
-
- return
-}
-
// TriggerClick, and return the result html
// ...then HTML5 parse it, diff the node tree
// (probably faster and cleaner than anything else)
func (d *Domino) TriggerClick(selector string) (newHTML string, ok bool, err error) {- var res goja.Value
- ch := make(chan int, 1)
+ res, err := d.Exec(`
+ var sel = '` + selector + `';
+ var el = document.querySelector(sel);
- d.loop.RunOnLoop(func(vm *goja.Runtime) {- res, err = vm.RunString(`
- var sel = '` + selector + `';
- console.log('sel=');- console.log(sel);
- var sell = document.querySelector(sel);
- if (sell._listeners && sell._listeners.click) {- var selfn = sell.click.bind(sell);
- if (selfn) {- selfn();
- }
- !!selfn;
- } else {- false;
- }
- `)
- ch <- 1
- })
- <- ch
+ console.log('query ' + sel);+ if (el._listeners && el._listeners.click) {+ var fn = el.click.bind(el);
- ok = fmt.Sprintf("%v", res) == "true"+ if (fn) {+ console.log(' call click handler...');+ fn();
+ }
- if ok {+ !!fn;
+ } else {+ false;
+ }
+ `, false)
+
+ if ok = res == "true"; ok {newHTML, ok, err = d.TrackChanges()
}
@@ -227,20 +203,20 @@
// Put change into html (e.g. from input field mutation)
func (d *Domino) PutAttr(selector, attr, val string) (ok bool, err error) {- res, err := d.vm.RunString(`
+ res, err := d.Exec(`
var sel = '` + selector + `';
- var sell = document.querySelector(sel);
- sell.attr('` + attr + `', '` + val + `');- !!sell;
- `)
+ var el = document.querySelector(sel);
+ el.attr('` + attr + `', '` + val + `');+ !!el;
+ `, false)
- ok = fmt.Sprintf("%v", res) == "true"+ ok = res == "true"
return
}
func (d *Domino) TrackChanges() (html string, changed bool, err error) {- html, err = d.Export("document.querySelector('html').innerHTML;")+ html, err = d.Exec("document.querySelector('html').innerHTML;", false) if err != nil {return
}
@@ -247,30 +223,6 @@
changed = d.outputHtml != html
d.outputHtml = html
return
-}
-
-// https://stackoverflow.com/a/26716182
-// TODO: eval is evil
-func (d *Domino) ExecInlinedScripts() (err error) {- return d.Exec(`
- navigator = {};-
- var scripts = Array.prototype.slice.call(document.getElementsByTagName("script"));- for (var i = 0; i < scripts.length; i++) {- if (scripts[i].src != "") {- var tag = document.createElement("script");- tag.src = scripts[i].src;
- document.getElementsByTagName("head")[0].appendChild(tag);- }
- else {- try {- eval.call(window, scripts[i].innerHTML);
- } catch(e) {- console.log(e);
- }
- }
- }
- `)
}
func Srcs(doc *nodes.Node) (srcs []string) {--- a/domino/domino_test.go
+++ b/domino/domino_test.go
@@ -23,25 +23,36 @@
func TestSimple(t *testing.T) {d := NewDomino(simpleHTML)
d.Start()
- script := `
- console.log('Hello!!');- var numberOne = 1;
+ s := `
+ var state = 'empty';
+ var a = 1;
+ b = 2;
`
- err := d.Exec(script)
+ _, err := d.Exec(s, true)
if err != nil { t.Fatalf("%v", err)}
- res, err := d.Export("numberOne+1")- t.Logf("res=%v", res)+ s2 := `
+ (function() {+ if (state !== 'empty') throw new Exception(state);
+
+ state = a + b;
+ })()
+ var a = 1;
+ b = 2;
+ `
+ _, err = d.Exec(s2, false)
if err != nil { t.Fatalf("%v", err)}
- if res != "2" {- t.Fatal()
- }
d.Stop()
}
+func TestGlobals(t *testing.T) {+ d := NewDomino(simpleHTML)
+ d.Start()
+}
+
func TestJQuery(t *testing.T) { buf, err := ioutil.ReadFile("jquery-3.5.1.js") if err != nil {@@ -66,11 +77,11 @@
var numberOne = 1;
`
_=buf
- err = d.Exec(string(buf) + ";" + script)
+ _, err = d.Exec(string(buf) + ";" + script, true)
if err != nil { t.Fatalf("%v", err)}
- res, err := d.Export("numberOne+1")+ res, err := d.Exec("numberOne+1", false) t.Logf("res=%v", res) if err != nil { t.Fatalf("%v", err)@@ -111,13 +122,13 @@
`
d := NewDomino(simpleHTML)
d.Start()
- err = d.Exec(SCRIPT)
+ _, err = d.Exec(SCRIPT, true)
if err != nil {t.Fatalf(err.Error())
}
time.Sleep(2 * time.Second)
- res, err := d.Export("$('h1').html()")+ res, err := d.Exec("$('h1').html()", false) if err != nil {t.Fatalf(err.Error())
}
@@ -148,13 +159,13 @@
`
d := NewDomino(simpleHTML)
d.Start()
- err = d.Exec(SCRIPT)
+ _, err = d.Exec(SCRIPT, true)
if err != nil {t.Fatalf(err.Error())
}
//time.Sleep(2 * time.Second)
- res, err := d.Export("$('h1').html()")+ res, err := d.Exec("$('h1').html()", false) if err != nil {t.Fatalf(err.Error())
}
@@ -161,6 +172,10 @@
if res != "Hello" {t.Fatalf(res)
}
+
+ if _, _, err = d.TrackChanges(); err != nil {+ t.Fatalf(err.Error())
+ }
_, changed, err := d.TriggerClick("h1") if err != nil {t.Fatalf(err.Error())
@@ -168,7 +183,7 @@
if changed {t.Fatal()
}
- res, err = d.Export("clicked")+ res, err = d.Exec("clicked", false) if err != nil {t.Fatalf(err.Error())
}
@@ -207,13 +222,13 @@
`
d := NewDomino(simpleHTML)
d.Start()
- err = d.Exec(SCRIPT)
+ _, err = d.Exec(SCRIPT, true)
if err != nil {t.Fatalf(err.Error())
}
time.Sleep(2 * time.Second)
- res, err := d.Export("$('h1').html()")+ res, err := d.Exec("$('h1').html()", false) if err != nil {t.Fatalf(err.Error())
}
@@ -221,7 +236,7 @@
t.Fatalf(res)
}*/
_=res
- res, err = d.Export("$('h1').html('minor updates :-)'); $('h1').html();")+ res, err = d.Exec("$('h1').html('minor updates :-)'); $('h1').html();", false) if err != nil {t.Fatalf(err.Error())
}
@@ -233,10 +248,14 @@
func TestTrackChanges(t *testing.T) {d := NewDomino(simpleHTML)
d.Start()
- err := d.Exec(``)
+ _, err := d.Exec(``, true)
if err != nil {t.Fatalf(err.Error())
}
+ // 0th time: init
+ if _, _, err = d.TrackChanges(); err != nil {+ t.Fatalf(err.Error())
+ }
// 1st time: no change
html, changed, err := d.TrackChanges()
if err != nil {@@ -259,7 +278,7 @@
if changed == true {t.Fatal()
}
- _, err = d.Export("document.getElementById('title').innerHTML='new title'; true;")+ _, err = d.Exec("document.getElementById('title').innerHTML='new title'; true;", false) if err != nil {t.Fatalf(err.Error())
}
@@ -280,7 +299,7 @@
d.Stop()
}
-func TestExecInlinedScripts(t *testing.T) {+/*func TestExecInlinedScripts(t *testing.T) {const h = `
<html>
<body>
@@ -305,9 +324,9 @@
t.Fatalf(res)
}
d.Stop()
-}
+}*/
-func TestWindowEqualsGlobal(t *testing.T) {+/*func TestWindowEqualsGlobal(t *testing.T) {const h = `
<html>
<body>
@@ -347,7 +366,7 @@
t.Fatalf(res)
}
d.Stop()
-}
+}*/
func TestES6(t *testing.T) {d := NewDomino(simpleHTML)
@@ -356,11 +375,11 @@
console.log('Hello!!');const numberOne = 1;
`
- err := d.Exec6(script)
+ _, err := d.Exec6(script)
if err != nil { t.Fatalf("%v", err)}
- res, err := d.Export("numberOne+1")+ res, err := d.Exec("numberOne+1", false) t.Logf("res=%v", res) if err != nil { t.Fatalf("%v", err)@@ -377,11 +396,11 @@
script := `
console.log('Hello!!')`
- err := d.Exec(script)
+ _, err := d.Exec(script, true)
if err != nil { t.Fatalf("%v", err)}
- res, err := d.Export("window === window.parent")+ res, err := d.Exec("window === window.parent", false) t.Logf("res=%v", res) if err != nil { t.Fatalf("%v", err)--- a/domino/main.js
+++ /dev/null
@@ -1,23 +1,0 @@
-
- global = {};- //global.__domino_frozen__ = true; // Must precede any require('domino')- var domino = require('domino-lib/index');- var Element = domino.impl.Element; // etc
-
- // JSDOM also knows the style tag
- // https://github.com/jsdom/jsdom/issues/2485
- Object.assign(this, domino.createWindow(s.html, 'http://example.com'));
- window = this;
- window.parent = window;
- window.top = window;
- window.self = window;
- addEventListener = function() {};- window.location.href = 'http://example.com';
- navigator = {};- HTMLElement = domino.impl.HTMLElement;
- // Fire DOMContentLoaded
- // to trigger $(document)readfy!!!!!!!
- document.close();
-
- console.log('Hello!!')-
\ No newline at end of file
--
⑨