use goja for elk

This commit is contained in:
Alexander Wang 2022-12-03 12:09:22 -08:00
parent b5dc40ce0f
commit c975ddcd03
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
2 changed files with 21 additions and 30 deletions

View file

@ -11,8 +11,7 @@ import (
"fmt" "fmt"
"math" "math"
"rogchap.com/v8go" "github.com/dop251/goja"
"oss.terrastruct.com/util-go/xdefer" "oss.terrastruct.com/util-go/xdefer"
"oss.terrastruct.com/util-go/go2" "oss.terrastruct.com/util-go/go2"
@ -88,30 +87,17 @@ type ELKLayoutOptions struct {
func Layout(ctx context.Context, g *d2graph.Graph) (err error) { func Layout(ctx context.Context, g *d2graph.Graph) (err error) {
defer xdefer.Errorf(&err, "failed to ELK layout") defer xdefer.Errorf(&err, "failed to ELK layout")
iso := v8go.NewIsolate() vm := goja.New()
global := v8go.NewObjectTemplate(iso)
// setTimeout is not defined by in v8go global console := vm.NewObject()
// As far as I can tell, it's not actually useful in elk.js if err := vm.Set("console", console); err != nil {
// The comment above one of the instances it's used is "why do we even need this"
// and it's a timeout of 0.
// If weird things happen though, look here.
setTimeout := v8go.NewFunctionTemplate(iso, func(info *v8go.FunctionCallbackInfo) *v8go.Value {
args := info.Args()
fn, _ := args[0].AsFunction()
receiver := v8go.NewObjectTemplate(iso)
s, _ := receiver.NewInstance(info.Context())
fn.Call(s)
return s.Value
})
global.Set("setTimeout", setTimeout, v8go.ReadOnly)
v8ctx := v8go.NewContext(iso, global)
if _, err := v8ctx.RunScript(elkJS, "elk.js"); err != nil {
return err return err
} }
if _, err := v8ctx.RunScript(setupJS, "setup.js"); err != nil {
if _, err := vm.RunString(elkJS); err != nil {
return err
}
if _, err := vm.RunString(setupJS); err != nil {
return err return err
} }
@ -205,37 +191,41 @@ func Layout(ctx context.Context, g *d2graph.Graph) (err error) {
loadScript := fmt.Sprintf(`var graph = %s`, raw) loadScript := fmt.Sprintf(`var graph = %s`, raw)
if _, err := v8ctx.RunScript(loadScript, "load.js"); err != nil { if _, err := vm.RunString(loadScript); err != nil {
return err return err
} }
val, err := v8ctx.RunScript(`elk.layout(graph) val, err := vm.RunString(`elk.layout(graph)
.then(s => s) .then(s => s)
.catch(s => s) .catch(s => s)
`, "layout.js") `)
if err != nil { if err != nil {
return err return err
} }
promise, err := val.AsPromise() p := val.Export()
if err != nil { if err != nil {
return err return err
} }
for promise.State() == v8go.Pending { promise := p.(*goja.Promise)
for promise.State() == goja.PromiseStatePending {
if err := ctx.Err(); err != nil { if err := ctx.Err(); err != nil {
return err return err
} }
continue continue
} }
jsonOut, err := promise.Result().MarshalJSON() jsonOut := promise.Result().Export().(map[string]interface{})
jsonBytes, err := json.Marshal(jsonOut)
if err != nil { if err != nil {
return err return err
} }
err = json.Unmarshal(jsonOut, &elkGraph) err = json.Unmarshal(jsonBytes, &elkGraph)
if err != nil { if err != nil {
return err return err
} }

View file

@ -1 +1,2 @@
var setTimeout = function(f) {f()};
const elk = new ELK(); const elk = new ELK();