Skip to content

Commit 8d9bf98

Browse files
committed
refactor
1 parent 2a56126 commit 8d9bf98

File tree

4 files changed

+274
-319
lines changed

4 files changed

+274
-319
lines changed

d2js/d2wasm/api.go

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//go:build js && wasm
2+
3+
package d2wasm
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
"syscall/js"
9+
)
10+
11+
type D2API struct {
12+
exports map[string]js.Func
13+
}
14+
15+
func NewD2API() *D2API {
16+
return &D2API{
17+
exports: make(map[string]js.Func),
18+
}
19+
}
20+
21+
func (api *D2API) Register(name string, fn func(args []js.Value) (interface{}, error)) {
22+
api.exports[name] = wrapWASMCall(fn)
23+
}
24+
25+
func (api *D2API) ExportTo(target js.Value) {
26+
d2Namespace := make(map[string]interface{})
27+
for name, fn := range api.exports {
28+
d2Namespace[name] = fn
29+
}
30+
target.Set("d2", js.ValueOf(d2Namespace))
31+
}
32+
33+
func wrapWASMCall(fn func(args []js.Value) (interface{}, error)) js.Func {
34+
return js.FuncOf(func(this js.Value, args []js.Value) (result any) {
35+
defer func() {
36+
if r := recover(); r != nil {
37+
resp := WASMResponse{
38+
Error: &WASMError{
39+
Message: fmt.Sprintf("panic recovered: %v", r),
40+
Code: 500,
41+
},
42+
}
43+
jsonResp, _ := json.Marshal(resp)
44+
result = string(jsonResp)
45+
}
46+
}()
47+
48+
data, err := fn(args)
49+
if err != nil {
50+
wasmErr, ok := err.(*WASMError)
51+
if !ok {
52+
wasmErr = &WASMError{
53+
Message: err.Error(),
54+
Code: 500,
55+
}
56+
}
57+
resp := WASMResponse{
58+
Error: wasmErr,
59+
}
60+
jsonResp, _ := json.Marshal(resp)
61+
return string(jsonResp)
62+
}
63+
64+
resp := WASMResponse{
65+
Data: data,
66+
}
67+
jsonResp, _ := json.Marshal(resp)
68+
return string(jsonResp)
69+
})
70+
}

d2js/d2wasm/functions.go

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//go:build js && wasm
2+
3+
package d2wasm
4+
5+
import (
6+
"encoding/json"
7+
"strings"
8+
"syscall/js"
9+
10+
"oss.terrastruct.com/d2/d2ast"
11+
"oss.terrastruct.com/d2/d2compiler"
12+
"oss.terrastruct.com/d2/d2format"
13+
"oss.terrastruct.com/d2/d2lsp"
14+
"oss.terrastruct.com/d2/d2oracle"
15+
"oss.terrastruct.com/d2/d2parser"
16+
"oss.terrastruct.com/d2/lib/version"
17+
)
18+
19+
func GetParentID(args []js.Value) (interface{}, error) {
20+
if len(args) < 1 {
21+
return nil, &WASMError{Message: "missing id argument", Code: 400}
22+
}
23+
24+
id := args[0].String()
25+
mk, err := d2parser.ParseMapKey(id)
26+
if err != nil {
27+
return nil, &WASMError{Message: err.Error(), Code: 400}
28+
}
29+
30+
if len(mk.Edges) > 0 {
31+
return "", nil
32+
}
33+
34+
if mk.Key != nil {
35+
if len(mk.Key.Path) == 1 {
36+
return "root", nil
37+
}
38+
mk.Key.Path = mk.Key.Path[:len(mk.Key.Path)-1]
39+
return strings.Join(mk.Key.StringIDA(), "."), nil
40+
}
41+
42+
return "", nil
43+
}
44+
45+
func GetObjOrder(args []js.Value) (interface{}, error) {
46+
if len(args) < 1 {
47+
return nil, &WASMError{Message: "missing dsl argument", Code: 400}
48+
}
49+
50+
dsl := args[0].String()
51+
g, _, err := d2compiler.Compile("", strings.NewReader(dsl), &d2compiler.CompileOptions{
52+
UTF16Pos: true,
53+
})
54+
if err != nil {
55+
return nil, &WASMError{Message: err.Error(), Code: 400}
56+
}
57+
58+
objOrder, err := d2oracle.GetObjOrder(g, nil)
59+
if err != nil {
60+
return nil, &WASMError{Message: err.Error(), Code: 500}
61+
}
62+
63+
return map[string]interface{}{
64+
"order": objOrder,
65+
}, nil
66+
}
67+
68+
func GetRefRanges(args []js.Value) (interface{}, error) {
69+
if len(args) < 4 {
70+
return nil, &WASMError{Message: "missing required arguments", Code: 400}
71+
}
72+
73+
var fs map[string]string
74+
if err := json.Unmarshal([]byte(args[0].String()), &fs); err != nil {
75+
return nil, &WASMError{Message: "invalid fs argument", Code: 400}
76+
}
77+
78+
file := args[1].String()
79+
key := args[2].String()
80+
81+
var boardPath []string
82+
if err := json.Unmarshal([]byte(args[3].String()), &boardPath); err != nil {
83+
return nil, &WASMError{Message: "invalid boardPath argument", Code: 400}
84+
}
85+
86+
ranges, importRanges, err := d2lsp.GetRefRanges(file, fs, boardPath, key)
87+
if err != nil {
88+
return nil, &WASMError{Message: err.Error(), Code: 500}
89+
}
90+
91+
return RefRangesResponse{
92+
Ranges: ranges,
93+
ImportRanges: importRanges,
94+
}, nil
95+
}
96+
97+
func Compile(args []js.Value) (interface{}, error) {
98+
if len(args) < 1 {
99+
return nil, &WASMError{Message: "missing script argument", Code: 400}
100+
}
101+
102+
script := args[0].String()
103+
g, _, err := d2compiler.Compile("", strings.NewReader(script), &d2compiler.CompileOptions{
104+
UTF16Pos: true,
105+
})
106+
if err != nil {
107+
if pe, ok := err.(*d2parser.ParseError); ok {
108+
return nil, &WASMError{Message: pe.Error(), Code: 400}
109+
}
110+
return nil, &WASMError{Message: err.Error(), Code: 500}
111+
}
112+
113+
newScript := d2format.Format(g.AST)
114+
if script != newScript {
115+
return map[string]string{"result": newScript}, nil
116+
}
117+
118+
return nil, nil
119+
}
120+
121+
func GetBoardAtPosition(args []js.Value) (interface{}, error) {
122+
if len(args) < 3 {
123+
return nil, &WASMError{Message: "missing required arguments", Code: 400}
124+
}
125+
126+
dsl := args[0].String()
127+
line := args[1].Int()
128+
column := args[2].Int()
129+
130+
boardPath, err := d2lsp.GetBoardAtPosition(dsl, d2ast.Position{
131+
Line: line,
132+
Column: column,
133+
})
134+
if err != nil {
135+
return nil, &WASMError{Message: err.Error(), Code: 500}
136+
}
137+
138+
return BoardPositionResponse{BoardPath: boardPath}, nil
139+
}
140+
141+
func Encode(args []js.Value) (interface{}, error) {
142+
if len(args) < 1 {
143+
return nil, &WASMError{Message: "missing script argument", Code: 400}
144+
}
145+
146+
script := args[0].String()
147+
return map[string]string{"result": script}, nil
148+
}
149+
150+
func Decode(args []js.Value) (interface{}, error) {
151+
if len(args) < 1 {
152+
return nil, &WASMError{Message: "missing script argument", Code: 400}
153+
}
154+
155+
script := args[0].String()
156+
return map[string]string{"result": script}, nil
157+
}
158+
159+
func GetVersion(args []js.Value) (interface{}, error) {
160+
return version.Version, nil
161+
}

d2js/d2wasm/types.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//go:build js && wasm
2+
3+
package d2wasm
4+
5+
import "oss.terrastruct.com/d2/d2ast"
6+
7+
type WASMResponse struct {
8+
Data interface{} `json:"data,omitempty"`
9+
Error *WASMError `json:"error,omitempty"`
10+
}
11+
12+
type WASMError struct {
13+
Message string `json:"message"`
14+
Code int `json:"code"`
15+
}
16+
17+
func (e *WASMError) Error() string {
18+
return e.Message
19+
}
20+
21+
type RefRangesResponse struct {
22+
Ranges []d2ast.Range `json:"ranges"`
23+
ImportRanges []d2ast.Range `json:"importRanges"`
24+
}
25+
26+
type BoardPositionResponse struct {
27+
BoardPath []string `json:"boardPath"`
28+
}

0 commit comments

Comments
 (0)