From 9f54c4302c4343d09920e70ac3f06d4cd15af986 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 14 Aug 2025 20:21:55 -0600 Subject: [PATCH 01/12] save --- d2js/d2wasm/functions.go | 45 +++++++++++++++++ d2js/d2wasm/types.go | 2 + d2js/js/examples/customizable.html | 80 ++++++++++++++++++++++++++++-- d2js/js/index.d.ts | 4 ++ d2js/js/test/unit/basic.test.js | 62 +++++++++++++++++++++++ 5 files changed, 189 insertions(+), 4 deletions(-) diff --git a/d2js/d2wasm/functions.go b/d2js/d2wasm/functions.go index 2d0599ba6b..61f2e1eb76 100644 --- a/d2js/d2wasm/functions.go +++ b/d2js/d2wasm/functions.go @@ -20,6 +20,8 @@ import ( "oss.terrastruct.com/d2/d2oracle" "oss.terrastruct.com/d2/d2parser" "oss.terrastruct.com/d2/d2renderers/d2animate" + "oss.terrastruct.com/d2/d2renderers/d2ascii" + "oss.terrastruct.com/d2/d2renderers/d2ascii/charset" "oss.terrastruct.com/d2/d2renderers/d2fonts" "oss.terrastruct.com/d2/d2renderers/d2svg" "oss.terrastruct.com/d2/d2renderers/d2svg/appendix" @@ -29,6 +31,7 @@ import ( "oss.terrastruct.com/d2/lib/textmeasure" "oss.terrastruct.com/d2/lib/urlenc" "oss.terrastruct.com/d2/lib/version" + "oss.terrastruct.com/util-go/go2" ) const DEFAULT_INPUT_PATH = "index" @@ -242,6 +245,12 @@ func Compile(args []js.Value) (interface{}, error) { compileOpts.Layout = input.Opts.Layout } + if input.Opts != nil && input.Opts.ASCII != nil && *input.Opts.ASCII { + if compileOpts.Layout == nil || *compileOpts.Layout == "dagre" { + compileOpts.Layout = go2.Pointer("elk") + } + } + renderOpts := &d2svg.RenderOpts{} if input.Opts != nil && input.Opts.Sketch != nil { renderOpts.Sketch = input.Opts.Sketch @@ -293,6 +302,8 @@ func Compile(args []js.Value) (interface{}, error) { AnimateInterval: input.Opts.AnimateInterval, Salt: input.Opts.Salt, NoXMLTag: input.Opts.NoXMLTag, + ASCII: input.Opts.ASCII, + ASCIIMode: input.Opts.ASCIIMode, }, }, nil } @@ -397,6 +408,40 @@ func Render(args []js.Value) (interface{}, error) { renderOpts.NoXMLTag = input.Opts.NoXMLTag } + if input.Opts != nil && input.Opts.ASCII != nil && *input.Opts.ASCII { + if !noChildren && animateInterval > 0 { + return nil, &WASMError{Message: "ASCII rendering does not support multi-board animation", Code: 400} + } + if !noChildren { + return nil, &WASMError{Message: "ASCII rendering does not support multi-board targets", Code: 400} + } + + artist := d2ascii.NewASCIIartist() + asciiOpts := &d2ascii.RenderOpts{} + if input.Opts.Scale != nil { + asciiOpts.Scale = input.Opts.Scale + } + // Set charset based on ASCII mode (default to "extended"/Unicode) + var charsetType charset.Type + asciiMode := "extended" // Default + if input.Opts.ASCIIMode != nil { + asciiMode = *input.Opts.ASCIIMode + } + switch asciiMode { + case "standard": + charsetType = charset.ASCII + default: // "extended" or any other value defaults to Unicode + charsetType = charset.Unicode + } + asciiOpts.Charset = charsetType + + out, err := artist.Render(diagram, asciiOpts) + if err != nil { + return nil, &WASMError{Message: fmt.Sprintf("ASCII render failed: %s", err.Error()), Code: 500} + } + return out, nil + } + forceAppendix := input.Opts != nil && input.Opts.ForceAppendix != nil && *input.Opts.ForceAppendix var boards [][]byte diff --git a/d2js/d2wasm/types.go b/d2js/d2wasm/types.go index b10e97c1fe..435efb3867 100644 --- a/d2js/d2wasm/types.go +++ b/d2js/d2wasm/types.go @@ -52,6 +52,8 @@ type RenderOptions struct { AnimateInterval *int64 `json:"animateInterval"` Salt *string `json:"salt"` NoXMLTag *bool `json:"noXMLTag"` + ASCII *bool `json:"ascii"` + ASCIIMode *string `json:"asciiMode"` } type CompileOptions struct { diff --git a/d2js/js/examples/customizable.html b/d2js/js/examples/customizable.html index afa6e60a37..3498181823 100644 --- a/d2js/js/examples/customizable.html +++ b/d2js/js/examples/customizable.html @@ -90,12 +90,30 @@ min-width: 100%; max-height: 90vh; } + + #output pre { + font-family: monospace; + white-space: pre; + overflow-x: auto; + background: #f5f5f5; + padding: 16px; + border-radius: 4px; + }
- +
@@ -137,6 +155,30 @@
+
+
+ +
+
+
+ + +
+ +
+