3
3
package d2wasm
4
4
5
5
import (
6
+ "context"
6
7
"encoding/json"
8
+ "fmt"
7
9
"strings"
8
10
"syscall/js"
9
11
10
12
"oss.terrastruct.com/d2/d2ast"
11
13
"oss.terrastruct.com/d2/d2compiler"
12
14
"oss.terrastruct.com/d2/d2format"
15
+ "oss.terrastruct.com/d2/d2graph"
16
+ "oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
17
+ "oss.terrastruct.com/d2/d2layouts/d2elklayout"
18
+ "oss.terrastruct.com/d2/d2lib"
13
19
"oss.terrastruct.com/d2/d2lsp"
14
20
"oss.terrastruct.com/d2/d2oracle"
15
21
"oss.terrastruct.com/d2/d2parser"
22
+ "oss.terrastruct.com/d2/d2renderers/d2fonts"
23
+ "oss.terrastruct.com/d2/d2renderers/d2svg"
24
+ "oss.terrastruct.com/d2/lib/log"
25
+ "oss.terrastruct.com/d2/lib/memfs"
26
+ "oss.terrastruct.com/d2/lib/textmeasure"
27
+ "oss.terrastruct.com/d2/lib/urlenc"
16
28
"oss.terrastruct.com/d2/lib/version"
29
+ "oss.terrastruct.com/util-go/go2"
17
30
)
18
31
19
32
func GetParentID (args []js.Value ) (interface {}, error ) {
@@ -96,26 +109,104 @@ func GetRefRanges(args []js.Value) (interface{}, error) {
96
109
97
110
func Compile (args []js.Value ) (interface {}, error ) {
98
111
if len (args ) < 1 {
99
- return nil , & WASMError {Message : "missing script argument" , Code : 400 }
112
+ return nil , & WASMError {Message : "missing JSON argument" , Code : 400 }
113
+ }
114
+ var input CompileRequest
115
+ if err := json .Unmarshal ([]byte (args [0 ].String ()), & input ); err != nil {
116
+ return nil , & WASMError {Message : "invalid JSON input" , Code : 400 }
100
117
}
101
118
102
- script := args [0 ].String ()
103
- g , _ , err := d2compiler .Compile ("" , strings .NewReader (script ), & d2compiler.CompileOptions {
104
- UTF16Pos : true ,
105
- })
119
+ if input .FS == nil {
120
+ return nil , & WASMError {Message : "missing 'fs' field in input JSON" , Code : 400 }
121
+ }
122
+
123
+ if _ , ok := input .FS ["index" ]; ! ok {
124
+ return nil , & WASMError {Message : "missing 'index' file in input fs" , Code : 400 }
125
+ }
126
+
127
+ fs , err := memfs .New (input .FS )
128
+ if err != nil {
129
+ return nil , & WASMError {Message : fmt .Sprintf ("invalid fs input: %s" , err .Error ()), Code : 400 }
130
+ }
131
+
132
+ ruler , err := textmeasure .NewRuler ()
133
+ if err != nil {
134
+ return nil , & WASMError {Message : fmt .Sprintf ("text ruler cannot be initialized: %s" , err .Error ()), Code : 500 }
135
+ }
136
+ ctx := log .WithDefault (context .Background ())
137
+ layoutFunc := d2dagrelayout .DefaultLayout
138
+ if input .Opts != nil && input .Opts .Layout != nil {
139
+ switch * input .Opts .Layout {
140
+ case "dagre" :
141
+ layoutFunc = d2dagrelayout .DefaultLayout
142
+ case "elk" :
143
+ layoutFunc = d2elklayout .DefaultLayout
144
+ default :
145
+ return nil , & WASMError {Message : fmt .Sprintf ("layout option '%s' not recognized" , * input .Opts .Layout ), Code : 400 }
146
+ }
147
+ }
148
+ layoutResolver := func (engine string ) (d2graph.LayoutGraph , error ) {
149
+ return layoutFunc , nil
150
+ }
151
+
152
+ renderOpts := & d2svg.RenderOpts {}
153
+ var fontFamily * d2fonts.FontFamily
154
+ if input .Opts != nil && input .Opts .Sketch != nil {
155
+ fontFamily = go2 .Pointer (d2fonts .HandDrawn )
156
+ renderOpts .Sketch = input .Opts .Sketch
157
+ }
158
+ if input .Opts != nil && input .Opts .ThemeID != nil {
159
+ renderOpts .ThemeID = input .Opts .ThemeID
160
+ }
161
+ diagram , g , err := d2lib .Compile (ctx , input .FS ["index" ], & d2lib.CompileOptions {
162
+ UTF16Pos : true ,
163
+ FS : fs ,
164
+ Ruler : ruler ,
165
+ LayoutResolver : layoutResolver ,
166
+ FontFamily : fontFamily ,
167
+ }, renderOpts )
106
168
if err != nil {
107
169
if pe , ok := err .(* d2parser.ParseError ); ok {
108
170
return nil , & WASMError {Message : pe .Error (), Code : 400 }
109
171
}
110
172
return nil , & WASMError {Message : err .Error (), Code : 500 }
111
173
}
112
174
113
- newScript := d2format .Format (g .AST )
114
- if script != newScript {
115
- return map [string ]string {"result" : newScript }, nil
175
+ input .FS ["index" ] = d2format .Format (g .AST )
176
+
177
+ return CompileResponse {
178
+ FS : input .FS ,
179
+ Diagram : * diagram ,
180
+ Graph : * g ,
181
+ }, nil
182
+ }
183
+
184
+ func Render (args []js.Value ) (interface {}, error ) {
185
+ if len (args ) < 1 {
186
+ return nil , & WASMError {Message : "missing JSON argument" , Code : 400 }
187
+ }
188
+ var input RenderRequest
189
+ if err := json .Unmarshal ([]byte (args [0 ].String ()), & input ); err != nil {
190
+ return nil , & WASMError {Message : "invalid JSON input" , Code : 400 }
191
+ }
192
+
193
+ if input .Diagram == nil {
194
+ return nil , & WASMError {Message : "missing 'diagram' field in input JSON" , Code : 400 }
195
+ }
196
+
197
+ renderOpts := & d2svg.RenderOpts {}
198
+ if input .Opts != nil && input .Opts .Sketch != nil {
199
+ renderOpts .Sketch = input .Opts .Sketch
200
+ }
201
+ if input .Opts != nil && input .Opts .ThemeID != nil {
202
+ renderOpts .ThemeID = input .Opts .ThemeID
203
+ }
204
+ out , err := d2svg .Render (input .Diagram , renderOpts )
205
+ if err != nil {
206
+ return nil , & WASMError {Message : fmt .Sprintf ("render failed: %s" , err .Error ()), Code : 500 }
116
207
}
117
208
118
- return nil , nil
209
+ return out , nil
119
210
}
120
211
121
212
func GetBoardAtPosition (args []js.Value ) (interface {}, error ) {
@@ -144,7 +235,13 @@ func Encode(args []js.Value) (interface{}, error) {
144
235
}
145
236
146
237
script := args [0 ].String ()
147
- return map [string ]string {"result" : script }, nil
238
+ encoded , err := urlenc .Encode (script )
239
+ // should never happen
240
+ if err != nil {
241
+ return nil , & WASMError {Message : err .Error (), Code : 500 }
242
+ }
243
+
244
+ return map [string ]string {"result" : encoded }, nil
148
245
}
149
246
150
247
func Decode (args []js.Value ) (interface {}, error ) {
@@ -153,6 +250,10 @@ func Decode(args []js.Value) (interface{}, error) {
153
250
}
154
251
155
252
script := args [0 ].String ()
253
+ script , err := urlenc .Decode (script )
254
+ if err != nil {
255
+ return nil , & WASMError {Message : err .Error (), Code : 500 }
256
+ }
156
257
return map [string ]string {"result" : script }, nil
157
258
}
158
259
@@ -189,7 +290,3 @@ func GetCompletions(args []js.Value) (interface{}, error) {
189
290
Items : items ,
190
291
}, nil
191
292
}
192
-
193
- type CompletionResponse struct {
194
- Items []map [string ]interface {} `json:"items"`
195
- }
0 commit comments