diff --git a/README.md b/README.md index ebf199e30..41b472a74 100644 --- a/README.md +++ b/README.md @@ -46,34 +46,63 @@ https://user-images.githubusercontent.com/3120367/206125010-bd1fea8e-248a-43e7-8 ## What does D2 look like? ```d2 -# Actors -hans: Hans Niemann +vars: { + d2-config: { + layout-engine: elk + # Terminal theme code + theme-id: 300 + } +} +network: { + cell tower: { + satellites: { + shape: stored_data + style.multiple: true + } -defendants: { - mc: Magnus Carlsen - playmagnus: Play Magnus Group - chesscom: Chess.com - naka: Hikaru Nakamura + transmitter - mc -> playmagnus: Owns majority - playmagnus <-> chesscom: Merger talks - chesscom -> naka: Sponsoring + satellites -> transmitter: send + satellites -> transmitter: send + satellites -> transmitter: send + } + + online portal: { + ui: {shape: hexagon} + } + + data processor: { + storage: { + shape: cylinder + style.multiple: true + } + } + + cell tower.transmitter -> data processor.storage: phone logs } -# Accusations -hans -> defendants: 'sueing for $100M' +user: { + shape: person + width: 130 +} -# Claim -defendants.naka -> hans: Accused of cheating on his stream -defendants.mc -> hans: Lost then withdrew with accusations -defendants.chesscom -> hans: 72 page report of cheating +user -> network.cell tower: make call +user -> network.online portal.ui: access { + style.stroke-dash: 3 +} + +api server -> network.online portal.ui: display +api server -> logs: persist +logs: {shape: page; style.multiple: true} + +network.data processor -> api server ``` -> There is syntax highlighting with the editor plugins linked below. +

+ D2 render example +

-D2 render example - -> Rendered with the TALA layout engine. +> Open in [playground](https://play.d2lang.com/?script=rVLLTsQwDLznKyJxbrWwtyLxFdyR1Zg2ahpHibvLCvXfcdqGfSHthVv8yIxn7APE1OhvpbV5qVryn7ZbQ60dnGjiCn1nPTYa3bCkn_Q7xtF6cJp7HFG3ZHCpLGFlTaP3u51kZjUrj3ykOKyYLTr5REeMhSMBS84yppKRXA9B-BJTRPNhgKEU-OSwHifHNjjp4DitxLNa-SP4NFpmjOoGXVdvl2VBR2_-sWeZgLwTp3SgyOCKnsnKa5PU4xd05OfyIWvTIVKLKdHZExEOHd4Z0p4E3oi2h25s8Ge764uZs4Rr4vqXMfQkAhx1SVanplQWtU0QMCbyEh-t4b7Rz_td6cuo267ryzWPMMiFgHN3XVdu1dkmaPM8K-EiLnGkASsDScj2mQqCFcvj4RGUsSnI_d70Z2GrCptYrVHZTRADXv80VWgL0bVvGfJMoH4A) > For more examples, see [./docs/examples](./docs/examples). @@ -231,6 +260,7 @@ let us know and we'll be happy to include it here! - **Logseq-D2**: [https://github.com/b-yp/logseq-d2](https://github.com/b-yp/logseq-d2) - **ent2d2**: [https://github.com/tmc/ent2d2](https://github.com/tmc/ent2d2) - **MkDocs Plugin**: [https://github.com/landmaj/mkdocs-d2-plugin](https://github.com/landmaj/mkdocs-d2-plugin) +- **Remark Plugin**: [https://github.com/mech-a/remark-d2](https://github.com/mech-a/remark-d2) ### Misc @@ -261,6 +291,12 @@ Do you have or see an open-source project with `.d2` files? Please submit a PR a this selected list of featured projects using D2. - [ElasticSearch](https://github.com/elastic/beats/blob/main/libbeat/publisher/queue/proxy/diagrams/broker.d2) +- [Sourcegraph](https://handbook.sourcegraph.com/departments/engineering/managed-services/telemetry-gateway/#dev-architecture-diagram) +- [Temporal](https://github.com/temporalio/temporal/blob/0be2681c994470c7c61ea88e4fcef89bb4024e58/docs/_assets/matching-context.d2) +- [Tauri](https://v2.tauri.app/concept/inter-process-communication/) + - Rust GUI framework (78.5k stars) +- [Intellij](https://github.com/JetBrains/intellij-community/blob/45bcfc17a3f3e0d8548bc69e922d4ca97ac21b2b/platform/settings/docs/topics/overview.md) +- [Coder](https://coder.com/blog/managing-templates-in-coder) - [UC Berkeley](https://github.com/ucb-bar/hammer/blob/2b5c04d7b7d9ee3c73575efcd7ee0698bd5bfa88/doc/Hammer-Use/hier.d2) - [Coronacheck](https://github.com/minvws/nl-covid19-coronacheck-app-ios/blob/e1567e9d1633b3273c537a105bff0e7d3a57ecfe/Diagrams/client-side-datamodel.d2) diff --git a/ci/release/aws/ensure.sh b/ci/release/aws/ensure.sh index 19ab6141b..794675998 100755 --- a/ci/release/aws/ensure.sh +++ b/ci/release/aws/ensure.sh @@ -241,8 +241,9 @@ create_windows_amd64() { 'Name=instance-state-name,Values=pending,running,stopping,stopped' "Name=tag:Name,Values=$REMOTE_NAME" \ | jq -r '.Reservations[].Instances[].State.Name') if [ -z "$state" ]; then + # public AMIs are deprecated every few months so just search the latest Windows Server one for recreating sh_c aws ec2 run-instances \ - --image-id=ami-0c5300e833c2b32f3 \ + --image-id=ami-03ea14ccbeab7b2d5 \ --count=1 \ --instance-type=t3.medium \ --security-groups=windows \ @@ -441,19 +442,22 @@ init_remote_windows() { header "$REMOTE_NAME" wait_remote_host_windows + # rsync was broken in this script last ran on 4/10/24. + # had to upgrade with `pacman -Syyu rsync` after + init_ps1=$(cat < script` and then open it with vim FGCOLOR=3 bigheader "WARNING: WINDOWS INITIALIZATION MUST BE COMPLETED MANUALLY OVER RDP AND POWERSHELL!" warn '1. Obtain Windows RDP password with:' diff --git a/ci/release/build_in_docker.sh b/ci/release/build_in_docker.sh index 034d842e4..cbfcbcdec 100755 --- a/ci/release/build_in_docker.sh +++ b/ci/release/build_in_docker.sh @@ -4,7 +4,7 @@ cd -- "$(dirname "$0")/../.." . ./ci/sub/lib.sh tag="$(sh_c docker build \ - --build-arg GOVERSION="1.20.8.linux-$ARCH" \ + --build-arg GOVERSION="1.22.2.linux-$ARCH" \ -qf ./ci/release/linux/Dockerfile ./ci/release/linux)" docker_run \ -e DRY_RUN \ diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 2d39449f0..56fb4e6b1 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -2,6 +2,14 @@ #### Improvements ๐Ÿงน +- Opacity 0 shapes no longer have a label mask which made any segment of connections going through them lower opacity [#1940](https://github.com/terrastruct/d2/pull/1940) +- Bidirectional connections are now animated in opposite directions rather than one direction [#1939](https://github.com/terrastruct/d2/pull/1939) + #### Bugfixes โ›‘๏ธ -- Fixes edge case of bad import syntax crashing using d2 as a library [1829](https://github.com/terrastruct/d2/pull/1829) +- Local relative icons are relative to the d2 file instead of CLI invoke path [#1924](https://github.com/terrastruct/d2/pull/1924) +- Custom label positions weren't being read when the width was smaller than the label [#1928](https://github.com/terrastruct/d2/pull/1928) +- Using `shape: circle` for arrowheads no longer removes all arrowheads along path in sketch mode [#1942](https://github.com/terrastruct/d2/pull/1942) +- Globs to null connections work [#1965](https://github.com/terrastruct/d2/pull/1965) +- Edge globs setting styles inherit correctly in child boards [#1967](https://github.com/terrastruct/d2/pull/1967) +- Board links imported with spread imports work [#1972](https://github.com/terrastruct/d2/pull/1972) diff --git a/ci/release/changelogs/v0.6.4.md b/ci/release/changelogs/v0.6.4.md new file mode 100644 index 000000000..69ef0268b --- /dev/null +++ b/ci/release/changelogs/v0.6.4.md @@ -0,0 +1,19 @@ +#### Features ๐Ÿš€ + +- `style.underline` works on connections [#1836](https://github.com/terrastruct/d2/pull/1836) +- `none` is added as an accepted value for `fill-pattern`. Previously there was no way to cancel the `fill-pattern` on select objects set by a theme that applies it (Origami) [#1882](https://github.com/terrastruct/d2/pull/1882) + +#### Improvements ๐Ÿงน + +- Dimensions can be set less than label dimensions [#1901](https://github.com/terrastruct/d2/pull/1901) +- Boards no longer inherit `label` fields from parents [#1838](https://github.com/terrastruct/d2/pull/1838) +- Prevents `near` targeting a child of a special object like grid cells, which wasn't doing anything [#1851](https://github.com/terrastruct/d2/pull/1851) + +#### Bugfixes โ›‘๏ธ + +- Theme flags on CLI apply to PDFs [#1894](https://github.com/terrastruct/d2/pull/1894) +- Fixes styles in connections not overriding styles set by globs [#1857](https://github.com/terrastruct/d2/pull/1857) +- Fixes `null` being set on a nested shape not working in certain cases when connections also pointed to that shape [#1830](https://github.com/terrastruct/d2/pull/1830) +- Fixes edge case of bad import syntax crashing using d2 as a library [#1829](https://github.com/terrastruct/d2/pull/1829) +- Fixes `style.fill` not applying to markdown [#1872](https://github.com/terrastruct/d2/pull/1872) +- Fixes compiler erroring on certain styles when the shape's `shape` value is not all lowercase (e.g. `Circle`) [#1887](https://github.com/terrastruct/d2/pull/1887) diff --git a/ci/release/changelogs/v0.6.5.md b/ci/release/changelogs/v0.6.5.md new file mode 100644 index 000000000..2e5452a3e --- /dev/null +++ b/ci/release/changelogs/v0.6.5.md @@ -0,0 +1,7 @@ +D2 0.6.5 has a hotfix for 0.6.4 breaking plugin compatibility. Also includes 2 compiler fixes regarding substitutions/vars. + +#### Bugfixes โ›‘๏ธ + +- Fix executable plugins that implement standalone router [#1910](https://github.com/terrastruct/d2/pull/1910) +- Fix compiler error with multiple nested spread substitutions [#1913](https://github.com/terrastruct/d2/pull/1913) +- Fix substitutions from imports into different scopes [#1914](https://github.com/terrastruct/d2/pull/1914) diff --git a/d2ast/d2ast.go b/d2ast/d2ast.go index 85a530c88..705e840ed 100644 --- a/d2ast/d2ast.go +++ b/d2ast/d2ast.go @@ -862,9 +862,6 @@ func (mk *Key) HasTripleGlob() bool { return true } } - if mk.EdgeIndex != nil && mk.EdgeIndex.Glob { - return true - } if mk.EdgeKey.HasTripleGlob() { return true } @@ -1025,6 +1022,7 @@ type EdgeIndex struct { } func (ei1 *EdgeIndex) Equals(ei2 *EdgeIndex) bool { + // TODO probably should be checking the values, but will wait until something breaks to change if ei1.Int != ei2.Int { return false } diff --git a/d2chaos/d2chaos.go b/d2chaos/d2chaos.go index 96f9cd906..337ac24ae 100644 --- a/d2chaos/d2chaos.go +++ b/d2chaos/d2chaos.go @@ -146,6 +146,10 @@ func (gs *dslGenState) edge() error { } } + if src == dst && gs.nodeShapes[dst] == d2target.ShapeSequenceDiagram { + return nil + } + srcArrow := "-" if gs.randBool() { srcArrow = "<" @@ -265,7 +269,7 @@ func (gs *dslGenState) randStr(n int, inKey bool) string { func (gs *dslGenState) randShape() string { for { s := shapes[gs.rand.Intn(len(shapes))] - if s != d2target.ShapeImage { + if s != d2target.ShapeImage && s != d2target.ShapeText { return s } } diff --git a/d2cli/main.go b/d2cli/main.go index 2b2c138d9..69c86bcd7 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -459,7 +459,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs if os.Getenv("D2_LSP_MODE") == "1" { // only the parse result is needed if running d2 for lsp, // if this, "fails", the AST is still valid and can be sent - // to vscode extention + // to vscode extension ast, err := d2lib.Parse(ctx, string(input), opts) type LspOutputData struct { @@ -529,7 +529,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs ext := getExportExtension(outputPath) switch ext { case GIF: - svg, pngs, err := renderPNGsForGIF(ctx, ms, plugin, renderOpts, ruler, page, diagram) + svg, pngs, err := renderPNGsForGIF(ctx, ms, plugin, renderOpts, ruler, page, inputPath, diagram) if err != nil { return nil, false, err } @@ -553,7 +553,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs path := []pdf.BoardTitle{ {Name: diagram.Root.Label, BoardID: "root"}, } - pdf, err := renderPDF(ctx, ms, plugin, renderOpts, outputPath, page, ruler, diagram, nil, path, pageMap, diagram.Root.Label != "") + pdf, err := renderPDF(ctx, ms, plugin, renderOpts, inputPath, outputPath, page, ruler, diagram, nil, path, pageMap, diagram.Root.Label != "") if err != nil { return pdf, false, err } @@ -574,7 +574,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs path := []pptx.BoardTitle{ {Name: "root", BoardID: "root", LinkToSlide: boardIdToIndex["root"] + 1}, } - svg, err := renderPPTX(ctx, ms, p, plugin, renderOpts, ruler, outputPath, page, diagram, path, boardIdToIndex) + svg, err := renderPPTX(ctx, ms, p, plugin, renderOpts, ruler, inputPath, outputPath, page, diagram, path, boardIdToIndex) if err != nil { return nil, false, err } @@ -808,7 +808,7 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug if !diagram.IsFolderOnly { start := time.Now() - out, err := _render(ctx, ms, plugin, opts, boardOutputPath, bundle, forceAppendix, page, ruler, diagram) + out, err := _render(ctx, ms, plugin, opts, inputPath, boardOutputPath, bundle, forceAppendix, page, ruler, diagram) if err != nil { return boards, err } @@ -824,7 +824,7 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug func renderSingle(ctx context.Context, ms *xmain.State, compileDur time.Duration, plugin d2plugin.Plugin, opts d2svg.RenderOpts, inputPath, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([][]byte, error) { start := time.Now() - out, err := _render(ctx, ms, plugin, opts, outputPath, bundle, forceAppendix, page, ruler, diagram) + out, err := _render(ctx, ms, plugin, opts, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram) if err != nil { return [][]byte{}, err } @@ -835,7 +835,7 @@ func renderSingle(ctx context.Context, ms *xmain.State, compileDur time.Duration return [][]byte{out}, nil } -func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([]byte, error) { +func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, inputPath, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([]byte, error) { toPNG := getExportExtension(outputPath) == PNG var scale *float64 if opts.Scale != nil { @@ -865,7 +865,7 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts cacheImages := ms.Env.Getenv("IMG_CACHE") == "1" l := simplelog.FromCmdLog(ms.Log) - svg, bundleErr := imgbundler.BundleLocal(ctx, l, svg, cacheImages) + svg, bundleErr := imgbundler.BundleLocal(ctx, l, inputPath, svg, cacheImages) if bundle { var bundleErr2 error svg, bundleErr2 = imgbundler.BundleRemote(ctx, l, svg, cacheImages) @@ -915,7 +915,7 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts return svg, nil } -func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram, doc *pdf.GoFPDF, boardPath []pdf.BoardTitle, pageMap map[string]int, includeNav bool) (svg []byte, err error) { +func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, inputPath, outputPath string, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram, doc *pdf.GoFPDF, boardPath []pdf.BoardTitle, pageMap map[string]int, includeNav bool) (svg []byte, err error) { var isRoot bool if doc == nil { doc = pdf.Init() @@ -936,10 +936,11 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt } svg, err = d2svg.Render(diagram, &d2svg.RenderOpts{ - Pad: opts.Pad, - Sketch: opts.Sketch, - Center: opts.Center, - Scale: scale, + Pad: opts.Pad, + Sketch: opts.Sketch, + Center: opts.Center, + Scale: scale, + ThemeID: opts.ThemeID, }) if err != nil { return nil, err @@ -952,7 +953,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt cacheImages := ms.Env.Getenv("IMG_CACHE") == "1" l := simplelog.FromCmdLog(ms.Log) - svg, bundleErr := imgbundler.BundleLocal(ctx, l, svg, cacheImages) + svg, bundleErr := imgbundler.BundleLocal(ctx, l, inputPath, svg, cacheImages) svg, bundleErr2 := imgbundler.BundleRemote(ctx, l, svg, cacheImages) bundleErr = multierr.Combine(bundleErr, bundleErr2) if bundleErr != nil { @@ -985,7 +986,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt Name: dl.Root.Label, BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, LAYERS, dl.Name}, "."), }) - _, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap, includeNav) + _, err := renderPDF(ctx, ms, plugin, opts, inputPath, "", page, ruler, dl, doc, path, pageMap, includeNav) if err != nil { return nil, err } @@ -995,7 +996,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt Name: dl.Root.Label, BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, SCENARIOS, dl.Name}, "."), }) - _, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap, includeNav) + _, err := renderPDF(ctx, ms, plugin, opts, inputPath, "", page, ruler, dl, doc, path, pageMap, includeNav) if err != nil { return nil, err } @@ -1005,7 +1006,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt Name: dl.Root.Label, BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, STEPS, dl.Name}, "."), }) - _, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap, includeNav) + _, err := renderPDF(ctx, ms, plugin, opts, inputPath, "", page, ruler, dl, doc, path, pageMap, includeNav) if err != nil { return nil, err } @@ -1021,7 +1022,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt return svg, nil } -func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Presentation, plugin d2plugin.Plugin, opts d2svg.RenderOpts, ruler *textmeasure.Ruler, outputPath string, page playwright.Page, diagram *d2target.Diagram, boardPath []pptx.BoardTitle, boardIDToIndex map[string]int) ([]byte, error) { +func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Presentation, plugin d2plugin.Plugin, opts d2svg.RenderOpts, ruler *textmeasure.Ruler, inputPath, outputPath string, page playwright.Page, diagram *d2target.Diagram, boardPath []pptx.BoardTitle, boardIDToIndex map[string]int) ([]byte, error) { var svg []byte if !diagram.IsFolderOnly { // gofpdf will print the png img with a slight filter @@ -1054,7 +1055,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present cacheImages := ms.Env.Getenv("IMG_CACHE") == "1" l := simplelog.FromCmdLog(ms.Log) - svg, bundleErr := imgbundler.BundleLocal(ctx, l, svg, cacheImages) + svg, bundleErr := imgbundler.BundleLocal(ctx, l, inputPath, svg, cacheImages) svg, bundleErr2 := imgbundler.BundleRemote(ctx, l, svg, cacheImages) bundleErr = multierr.Combine(bundleErr, bundleErr2) if bundleErr != nil { @@ -1119,7 +1120,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present BoardID: boardID, LinkToSlide: boardIDToIndex[boardID] + 1, }) - _, err := renderPPTX(ctx, ms, presentation, plugin, opts, ruler, "", page, dl, path, boardIDToIndex) + _, err := renderPPTX(ctx, ms, presentation, plugin, opts, ruler, inputPath, "", page, dl, path, boardIDToIndex) if err != nil { return nil, err } @@ -1131,7 +1132,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present BoardID: boardID, LinkToSlide: boardIDToIndex[boardID] + 1, }) - _, err := renderPPTX(ctx, ms, presentation, plugin, opts, ruler, "", page, dl, path, boardIDToIndex) + _, err := renderPPTX(ctx, ms, presentation, plugin, opts, ruler, inputPath, "", page, dl, path, boardIDToIndex) if err != nil { return nil, err } @@ -1143,7 +1144,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present BoardID: boardID, LinkToSlide: boardIDToIndex[boardID] + 1, }) - _, err := renderPPTX(ctx, ms, presentation, plugin, opts, ruler, "", page, dl, path, boardIDToIndex) + _, err := renderPPTX(ctx, ms, presentation, plugin, opts, ruler, inputPath, "", page, dl, path, boardIDToIndex) if err != nil { return nil, err } @@ -1275,7 +1276,7 @@ func buildBoardIDToIndex(diagram *d2target.Diagram, dictionary map[string]int, p return dictionary } -func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, ruler *textmeasure.Ruler, page playwright.Page, diagram *d2target.Diagram) (svg []byte, pngs [][]byte, err error) { +func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, ruler *textmeasure.Ruler, page playwright.Page, inputPath string, diagram *d2target.Diagram) (svg []byte, pngs [][]byte, err error) { if !diagram.IsFolderOnly { var scale *float64 @@ -1301,7 +1302,7 @@ func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plug cacheImages := ms.Env.Getenv("IMG_CACHE") == "1" l := simplelog.FromCmdLog(ms.Log) - svg, bundleErr := imgbundler.BundleLocal(ctx, l, svg, cacheImages) + svg, bundleErr := imgbundler.BundleLocal(ctx, l, inputPath, svg, cacheImages) svg, bundleErr2 := imgbundler.BundleRemote(ctx, l, svg, cacheImages) bundleErr = multierr.Combine(bundleErr, bundleErr2) if bundleErr != nil { @@ -1318,21 +1319,21 @@ func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plug } for _, dl := range diagram.Layers { - _, layerPNGs, err := renderPNGsForGIF(ctx, ms, plugin, opts, ruler, page, dl) + _, layerPNGs, err := renderPNGsForGIF(ctx, ms, plugin, opts, ruler, page, inputPath, dl) if err != nil { return nil, nil, err } pngs = append(pngs, layerPNGs...) } for _, dl := range diagram.Scenarios { - _, scenarioPNGs, err := renderPNGsForGIF(ctx, ms, plugin, opts, ruler, page, dl) + _, scenarioPNGs, err := renderPNGsForGIF(ctx, ms, plugin, opts, ruler, page, inputPath, dl) if err != nil { return nil, nil, err } pngs = append(pngs, scenarioPNGs...) } for _, dl := range diagram.Steps { - _, stepsPNGs, err := renderPNGsForGIF(ctx, ms, plugin, opts, ruler, page, dl) + _, stepsPNGs, err := renderPNGsForGIF(ctx, ms, plugin, opts, ruler, page, inputPath, dl) if err != nil { return nil, nil, err } diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 5b314470f..dcf690903 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -69,6 +69,7 @@ func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) { g := d2graph.NewGraph() g.AST = ast + g.BaseAST = ast c.compileBoard(g, m) if len(c.err.Errors) > 0 { return nil, c.err @@ -90,6 +91,7 @@ func (c *compiler) compileBoard(g *d2graph.Graph, ir *d2ir.Map) *d2graph.Graph { c.validateLabels(g) c.validateNear(g) c.validateEdges(g) + c.validatePositionsCompatibility(g) c.compileBoardsField(g, ir, "layers") c.compileBoardsField(g, ir, "scenarios") @@ -121,7 +123,7 @@ func (c *compiler) compileBoardsField(g *d2graph.Graph, ir *d2ir.Map, fieldName g2 := d2graph.NewGraph() g2.Parent = g g2.AST = f.Map().AST().(*d2ast.Map) - g2.BaseAST = findFieldAST(g.AST, f) + g2.BaseAST = findFieldAST(g.BaseAST, f) c.compileBoard(g2, f.Map()) g2.Name = f.Name switch fieldName { @@ -337,11 +339,11 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) { } if obj.Parent != nil { - if obj.Parent.Shape.Value == d2target.ShapeSQLTable { + if strings.EqualFold(obj.Parent.Shape.Value, d2target.ShapeSQLTable) { c.errorf(f.LastRef().AST(), "sql_table columns cannot have children") return } - if obj.Parent.Shape.Value == d2target.ShapeClass { + if strings.EqualFold(obj.Parent.Shape.Value, d2target.ShapeClass) { c.errorf(f.LastRef().AST(), "class fields cannot have children") return } @@ -510,7 +512,7 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) { return } attrs.Shape.Value = scalar.ScalarString() - if attrs.Shape.Value == d2target.ShapeCode { + if strings.EqualFold(attrs.Shape.Value, d2target.ShapeCode) { // Explicit code shape is plaintext. attrs.Language = d2target.ShapeText } @@ -1008,12 +1010,12 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) { } } if obj.Style.DoubleBorder != nil { - if obj.Shape.Value != "" && obj.Shape.Value != d2target.ShapeSquare && obj.Shape.Value != d2target.ShapeRectangle && obj.Shape.Value != d2target.ShapeCircle && obj.Shape.Value != d2target.ShapeOval { + if obj.Shape.Value != "" && !strings.EqualFold(obj.Shape.Value, d2target.ShapeSquare) && !strings.EqualFold(obj.Shape.Value, d2target.ShapeRectangle) && !strings.EqualFold(obj.Shape.Value, d2target.ShapeCircle) && !strings.EqualFold(obj.Shape.Value, d2target.ShapeOval) { c.errorf(obj.Style.DoubleBorder.MapKey, `key "double-border" can only be applied to squares, rectangles, circles, ovals`) } } case "shape": - if obj.Shape.Value == d2target.ShapeImage && obj.Icon == nil { + if strings.EqualFold(obj.Shape.Value, d2target.ShapeImage) && obj.Icon == nil { c.errorf(f.LastPrimaryKey(), `image shape must include an "icon" field`) } @@ -1023,14 +1025,14 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) { c.errorf(f.LastPrimaryKey(), fmt.Sprintf(`invalid shape, can only set "%s" for arrowheads`, obj.Shape.Value)) } case "constraint": - if obj.Shape.Value != d2target.ShapeSQLTable { + if !strings.EqualFold(obj.Shape.Value, d2target.ShapeSQLTable) { c.errorf(f.LastPrimaryKey(), `"constraint" keyword can only be used in "sql_table" shapes`) } } return } - if obj.Shape.Value == d2target.ShapeImage { + if strings.EqualFold(obj.Shape.Value, d2target.ShapeImage) { c.errorf(f.LastRef().AST(), "image shapes cannot have children.") return } @@ -1043,7 +1045,7 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) { func (c *compiler) validateLabels(g *d2graph.Graph) { for _, obj := range g.Objects { - if obj.Shape.Value != d2target.ShapeText { + if !strings.EqualFold(obj.Shape.Value, d2target.ShapeText) { continue } if obj.Attributes.Language != "" { @@ -1097,6 +1099,14 @@ func (c *compiler) validateNear(g *d2graph.Graph) { continue } } + if nearObj.ClosestGridDiagram() != nil { + c.errorf(obj.NearKey, "near keys cannot be set to descendants of special objects, like grid cells") + continue + } + if nearObj.OuterSequenceDiagram() != nil { + c.errorf(obj.NearKey, "near keys cannot be set to descendants of special objects, like sequence diagram actors") + continue + } } else if isConst { if obj.Parent != g.Root { c.errorf(obj.NearKey, "constant near keys can only be set on root level shapes") @@ -1122,6 +1132,26 @@ func (c *compiler) validateNear(g *d2graph.Graph) { } +func (c *compiler) validatePositionsCompatibility(g *d2graph.Graph) { + for _, o := range g.Objects { + for _, pos := range []*d2graph.Scalar{o.Top, o.Left} { + if pos != nil { + if o.Parent != nil { + if strings.EqualFold(o.Parent.Shape.Value, d2target.ShapeHierarchy) { + c.errorf(pos.MapKey, `position keywords cannot be used with shape "hierarchy"`) + } + if o.OuterSequenceDiagram() != nil { + c.errorf(pos.MapKey, `position keywords cannot be used inside shape "sequence_diagram"`) + } + if o.Parent.GridColumns != nil || o.Parent.GridRows != nil { + c.errorf(pos.MapKey, `position keywords cannot be used with grids`) + } + } + } + } + } +} + func (c *compiler) validateEdges(g *d2graph.Graph) { for _, edge := range g.Edges { // edges from a grid to something outside is ok diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index c74398934..2350f1aba 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -10,6 +10,7 @@ import ( "oss.terrastruct.com/util-go/assert" "oss.terrastruct.com/util-go/diff" + "oss.terrastruct.com/util-go/mapfs" "oss.terrastruct.com/d2/d2compiler" "oss.terrastruct.com/d2/d2format" @@ -23,6 +24,8 @@ func TestCompile(t *testing.T) { testCases := []struct { name string text string + // For tests that use imports, define `index.d2` as text and other files here + files map[string]string expErr string assertions func(t *testing.T, g *d2graph.Graph) @@ -259,7 +262,7 @@ containers: { } } `, - expErr: `d2/testdata/d2compiler/TestCompile/invalid-fill-pattern.d2:3:19: expected "fill-pattern" to be one of: dots, lines, grain, paper`, + expErr: `d2/testdata/d2compiler/TestCompile/invalid-fill-pattern.d2:3:19: expected "fill-pattern" to be one of: none, dots, lines, grain, paper`, }, { name: "shape_unquoted_hex", @@ -1607,6 +1610,17 @@ d2/testdata/d2compiler/TestCompile/near-invalid.d2:14:9: near keys cannot be set `, expErr: `d2/testdata/d2compiler/TestCompile/near_bad_constant.d2:1:9: near key "txop-center" must be the absolute path to a shape or one of the following constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right`, }, + { + name: "near_special", + + text: `x.near: z.x +z: { + grid-rows: 1 + x +} +`, + expErr: `d2/testdata/d2compiler/TestCompile/near_special.d2:1:9: near keys cannot be set to descendants of special objects, like grid cells`, + }, { name: "near_bad_connected", @@ -2837,15 +2851,96 @@ y.source-arrowhead.shape: cf-one expErr: `d2/testdata/d2compiler/TestCompile/no_arrowheads_in_shape.d2:1:3: "target-arrowhead" can only be used on connections d2/testdata/d2compiler/TestCompile/no_arrowheads_in_shape.d2:2:3: "source-arrowhead" can only be used on connections`, }, + { + name: "shape-hierarchy", + text: `x: { + shape: hierarchy + a -> b +} +`, + }, + { + name: "fixed-pos-shape-hierarchy", + text: `x: { + shape: hierarchy + a -> b + a.top: 20 + a.left: 20 +} +`, + expErr: `d2/testdata/d2compiler/TestCompile/fixed-pos-shape-hierarchy.d2:4:2: position keywords cannot be used with shape "hierarchy" +d2/testdata/d2compiler/TestCompile/fixed-pos-shape-hierarchy.d2:5:2: position keywords cannot be used with shape "hierarchy"`, + }, + { + name: "vars-in-imports", + text: `dev: { + vars: { + env: Dev + } + ...@template.d2 +} + +qa: { + vars: { + env: Qa + } + ...@template.d2 +} +`, + files: map[string]string{ + "template.d2": `env: { + label: ${env} Environment + vm: { + label: My Virtual machine! + } +}`, + }, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "dev.env", g.Objects[1].AbsID()) + tassert.Equal(t, "Dev Environment", g.Objects[1].Label.Value) + tassert.Equal(t, "qa.env", g.Objects[2].AbsID()) + tassert.Equal(t, "Qa Environment", g.Objects[2].Label.Value) + }, + }, + { + name: "spread-import-link", + text: `k + +layers: { + x: {...@x} +}`, + files: map[string]string{ + "x.d2": `a.link: layers.b +layers: { + b: { + d + } +}`, + }, + }, } for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() - + opts := &d2compiler.CompileOptions{} + if tc.files != nil { + tc.files["index.d2"] = tc.text + renamed := make(map[string]string) + for file, content := range tc.files { + renamed[fmt.Sprintf("d2/testdata/d2compiler/TestCompile/%v", file)] = content + } + fs, err := mapfs.New(renamed) + assert.Success(t, err) + t.Cleanup(func() { + err = fs.Close() + assert.Success(t, err) + }) + opts.FS = fs + } d2Path := fmt.Sprintf("d2/testdata/d2compiler/%v.d2", t.Name()) - g, _, err := d2compiler.Compile(d2Path, strings.NewReader(tc.text), nil) + g, _, err := d2compiler.Compile(d2Path, strings.NewReader(tc.text), opts) if tc.expErr != "" { if err == nil { t.Fatalf("expected error with: %q", tc.expErr) @@ -2991,6 +3086,22 @@ steps: { assert.True(t, g.IsFolderOnly) }, }, + { + name: "no-inherit-label", + run: func(t *testing.T) { + g, _ := assertCompile(t, ` +label: hi + +steps: { + 1: { + RJ + } +} +`, "") + assert.True(t, g.Root.Label.MapKey != nil) + assert.True(t, g.Steps[0].Root.Label.MapKey == nil) + }, + }, { name: "scenarios_edge_index", run: func(t *testing.T) { @@ -3239,6 +3350,17 @@ y: null assert.Equal(t, 0, len(g.Edges)) }, }, + { + name: "delete-nested-connection", + run: func(t *testing.T) { + g, _ := assertCompile(t, ` +a -> b.c +b.c: null +`, "") + assert.Equal(t, 2, len(g.Objects)) + assert.Equal(t, 0, len(g.Edges)) + }, + }, { name: "delete-multiple-connections", run: func(t *testing.T) { @@ -3424,6 +3546,24 @@ hi: "1 ${x} 2" assert.Equal(t, "1 im a var 2", g.Objects[0].Label.Value) }, }, + { + name: "double-border", + run: func(t *testing.T) { + assertCompile(t, ` +a.shape: Circle +a.style.double-border: true +`, "") + }, + }, + { + name: "invalid-double-border", + run: func(t *testing.T) { + assertCompile(t, ` +a.shape: hexagon +a.style.double-border: true +`, `d2/testdata/d2compiler/TestCompile2/vars/basic/invalid-double-border.d2:3:1: key "double-border" can only be applied to squares, rectangles, circles, ovals`) + }, + }, { name: "single-quoted", run: func(t *testing.T) { @@ -4329,6 +4469,29 @@ container_2: { assert.Equal(t, 4, len(g.Objects)) }, }, + { + name: "override-edge/1", + run: func(t *testing.T) { + g, _ := assertCompile(t, ` +(* -> *)[*].style.stroke: red +(* -> *)[*].style.stroke: green +a -> b +`, ``) + assert.Equal(t, "green", g.Edges[0].Attributes.Style.Stroke.Value) + }, + }, + { + name: "override-edge/2", + run: func(t *testing.T) { + g, _ := assertCompile(t, ` +(* -> *)[*].style.stroke: red +a -> b: {style.stroke: green} +a -> b +`, ``) + assert.Equal(t, "green", g.Edges[0].Attributes.Style.Stroke.Value) + assert.Equal(t, "red", g.Edges[1].Attributes.Style.Stroke.Value) + }, + }, } for _, tc := range tca { diff --git a/d2exporter/export.go b/d2exporter/export.go index 6c25d5b8f..d01147af9 100644 --- a/d2exporter/export.go +++ b/d2exporter/export.go @@ -345,6 +345,9 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection if edge.Style.Bold != nil { connection.Bold, _ = strconv.ParseBool(edge.Style.Bold.Value) } + if edge.Style.Underline != nil { + connection.Underline, _ = strconv.ParseBool(edge.Style.Underline.Value) + } if theme != nil && theme.SpecialRules.Mono { connection.FontFamily = "mono" } diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index b70c887bd..da808ecfd 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -470,7 +470,7 @@ func (obj *Object) GetFill() string { return color.N7 } - if shape == "" || strings.EqualFold(shape, d2target.ShapeSquare) || strings.EqualFold(shape, d2target.ShapeCircle) || strings.EqualFold(shape, d2target.ShapeOval) || strings.EqualFold(shape, d2target.ShapeRectangle) { + if shape == "" || strings.EqualFold(shape, d2target.ShapeSquare) || strings.EqualFold(shape, d2target.ShapeCircle) || strings.EqualFold(shape, d2target.ShapeOval) || strings.EqualFold(shape, d2target.ShapeRectangle) || strings.EqualFold(shape, d2target.ShapeHierarchy) { if level == 1 { if !obj.IsContainer() { return color.B6 @@ -1048,15 +1048,6 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R // resizes the object to fit content of the given width and height in its inner box with the given padding. // this accounts for the shape of the object, and if there is a desired width or height set for the object func (obj *Object) SizeToContent(contentWidth, contentHeight, paddingX, paddingY float64) { - var desiredWidth int - var desiredHeight int - if obj.WidthAttr != nil { - desiredWidth, _ = strconv.Atoi(obj.WidthAttr.Value) - } - if obj.HeightAttr != nil { - desiredHeight, _ = strconv.Atoi(obj.HeightAttr.Value) - } - dslShape := strings.ToLower(obj.Shape.Value) shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape] s := shape.NewShape(shapeType, geo.NewBox(geo.NewPoint(0, 0), contentWidth, contentHeight)) @@ -1068,8 +1059,28 @@ func (obj *Object) SizeToContent(contentWidth, contentHeight, paddingX, paddingY } else { fitWidth, fitHeight = s.GetDimensionsToFit(contentWidth, contentHeight, paddingX, paddingY) } - obj.Width = math.Max(float64(desiredWidth), fitWidth) - obj.Height = math.Max(float64(desiredHeight), fitHeight) + + var desiredWidth int + if obj.WidthAttr != nil { + desiredWidth, _ = strconv.Atoi(obj.WidthAttr.Value) + obj.Width = float64(desiredWidth) + } else { + obj.Width = fitWidth + } + + var desiredHeight int + if obj.HeightAttr != nil { + desiredHeight, _ = strconv.Atoi(obj.HeightAttr.Value) + obj.Height = float64(desiredHeight) + } else { + obj.Height = fitHeight + } + + if obj.SQLTable != nil || obj.Class != nil || obj.Language != "" { + obj.Width = math.Max(float64(desiredWidth), fitWidth) + obj.Height = math.Max(float64(desiredHeight), fitHeight) + } + if s.AspectRatio1() { sideLength := math.Max(obj.Width, obj.Height) obj.Width = sideLength @@ -1816,6 +1827,7 @@ var LabelPositionsMapping = map[string]label.Position{ } var FillPatterns = []string{ + "none", "dots", "lines", "grain", diff --git a/d2graph/serde.go b/d2graph/serde.go index 88c3abd67..6b1006c31 100644 --- a/d2graph/serde.go +++ b/d2graph/serde.go @@ -28,7 +28,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error { } var root Object - convert(sg.Root, &root) + Convert(sg.Root, &root) g.Root = &root root.Graph = g g.RootLevel = sg.RootLevel @@ -38,7 +38,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error { var objects []*Object for _, so := range sg.Objects { var o Object - if err := convert(so, &o); err != nil { + if err := Convert(so, &o); err != nil { return err } o.Graph = g @@ -67,7 +67,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error { var edges []*Edge for _, se := range sg.Edges { var e Edge - if err := convert(se, &e); err != nil { + if err := Convert(se, &e); err != nil { return err } @@ -108,7 +108,7 @@ func SerializeGraph(g *Graph) ([]byte, error) { var sedges []SerializedEdge for _, e := range g.Edges { - se, err := toSerializedEdge(e) + se, err := ToSerializedEdge(e) if err != nil { return nil, err } @@ -121,7 +121,7 @@ func SerializeGraph(g *Graph) ([]byte, error) { func toSerializedObject(o *Object) (SerializedObject, error) { var so SerializedObject - if err := convert(o, &so); err != nil { + if err := Convert(o, &so); err != nil { return nil, err } @@ -138,9 +138,9 @@ func toSerializedObject(o *Object) (SerializedObject, error) { return so, nil } -func toSerializedEdge(e *Edge) (SerializedEdge, error) { +func ToSerializedEdge(e *Edge) (SerializedEdge, error) { var se SerializedEdge - if err := convert(e, &se); err != nil { + if err := Convert(e, &se); err != nil { return nil, err } @@ -154,7 +154,7 @@ func toSerializedEdge(e *Edge) (SerializedEdge, error) { return se, nil } -func convert[T, Q any](from T, to *Q) error { +func Convert[T, Q any](from T, to *Q) error { b, err := json.Marshal(from) if err != nil { return err diff --git a/d2ir/compile.go b/d2ir/compile.go index 37d3445a9..b05cda85c 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -31,8 +31,7 @@ type compiler struct { imports []string // importStack is used to detect cyclic imports. importStack []string - // importCache enables reuse of files imported multiple times. - importCache map[string]*Map + seenImports map[string]struct{} utf16Pos bool // Stack of globs that must be recomputed at each new object in and below the current scope. @@ -62,7 +61,7 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, []string, error) { err: &d2parser.ParseError{}, fs: opts.FS, - importCache: make(map[string]*Map), + seenImports: make(map[string]struct{}), utf16Pos: opts.UTF16Pos, } m := &Map{} @@ -127,14 +126,21 @@ func (c *compiler) compileSubstitutions(m *Map, varsStack []*Map) { varsStack = append([]*Map{f.Map()}, varsStack...) } } - for _, f := range m.Fields { + for i := 0; i < len(m.Fields); i++ { + f := m.Fields[i] if f.Primary() != nil { - c.resolveSubstitutions(varsStack, f) + removed := c.resolveSubstitutions(varsStack, f) + if removed { + i-- + } } if arr, ok := f.Composite.(*Array); ok { for _, val := range arr.Values { if scalar, ok := val.(*Scalar); ok { - c.resolveSubstitutions(varsStack, scalar) + removed := c.resolveSubstitutions(varsStack, scalar) + if removed { + i-- + } } } } else if f.Map() != nil { @@ -213,7 +219,7 @@ func (c *compiler) validateConfigs(configs *Field) { } } -func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) { +func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) (removedField bool) { var subbed bool var resolvedField *Field @@ -264,6 +270,7 @@ func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) { for i, f2 := range m.Fields { if n == f2 { m.Fields = append(m.Fields[:i], m.Fields[i+1:]...) + removedField = true break } } @@ -334,6 +341,7 @@ func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) { s.Coalesce() } } + return removedField } func (c *compiler) resolveSubstitution(vars *Map, substitution *d2ast.Substitution) *Field { @@ -361,6 +369,9 @@ func (c *compiler) overlay(base *Map, f *Field) { return } base = base.CopyBase(f) + // Certain fields should never carry forward. + // If you give your scenario a label, you don't want all steps in a scenario to be labeled the same. + base.DeleteField("label") OverlayMap(base, f.Map()) f.Composite = base } @@ -381,6 +392,9 @@ func (g *globContext) prefixed(dst *Map) *globContext { if len(prefix.Path) > 0 { g2.refctx.Key.Key = prefix } + if !g2.refctx.Key.HasTripleGlob() && g2.refctx.Key.EdgeKey != nil { + prefix.Path = append(prefix.Path, g2.refctx.Key.EdgeKey.Path...) + } return g2 } @@ -410,6 +424,7 @@ func (c *compiler) ampersandFilterMap(dst *Map, ast, scopeAST *d2ast.Map) bool { ks = d2format.Format(d2ast.MakeKeyPath(BoardIDA(dst))) } delete(gctx.appliedFields, ks) + delete(gctx.appliedEdges, ks) return false } } @@ -497,6 +512,7 @@ func (c *compiler) compileMap(dst *Map, ast, scopeAST *d2ast.Map) { } OverlayMap(dst, impn.Map()) + c.updateLinks(dst) if impnf, ok := impn.(*Field); ok { if impnf.Primary_ != nil { @@ -979,7 +995,7 @@ func (c *compiler) compileEdges(refctx *RefContext) { func (c *compiler) _compileEdges(refctx *RefContext) { eida := NewEdgeIDs(refctx.Key) for i, eid := range eida { - if refctx.Key != nil && refctx.Key.Value.Null != nil { + if !eid.Glob && (refctx.Key.Primary.Null != nil || refctx.Key.Value.Null != nil) { refctx.ScopeMap.DeleteEdge(eid) continue } @@ -997,6 +1013,10 @@ func (c *compiler) _compileEdges(refctx *RefContext) { continue } for _, e := range ea { + if refctx.Key.Primary.Null != nil || refctx.Key.Value.Null != nil { + refctx.ScopeMap.DeleteEdge(e.ID) + continue + } e.References = append(e.References, &EdgeReference{ Context_: refctx, DueToGlob_: len(c.globRefContextStack) > 0, diff --git a/d2ir/d2ir.go b/d2ir/d2ir.go index 5a21c549e..1ab518acc 100644 --- a/d2ir/d2ir.go +++ b/d2ir/d2ir.go @@ -950,13 +950,20 @@ func (m *Map) DeleteField(ida ...string) *Field { } if len(rest) == 0 { for _, fr := range f.References { - for _, e := range m.Edges { - for _, er := range e.References { - if er.Context_ == fr.Context_ { - m.DeleteEdge(e.ID) - break + currM := m + for currM != nil { + for _, e := range currM.Edges { + for _, er := range e.References { + if er.Context_ == fr.Context_ { + currM.DeleteEdge(e.ID) + break + } } } + if NodeBoardKind(currM) != "" { + break + } + currM = ParentMap(currM) } } m.Fields = append(m.Fields[:i], m.Fields[i+1:]...) @@ -1087,7 +1094,7 @@ func (m *Map) getEdges(eid *EdgeID, refctx *RefContext, gctx *globContext, ea *[ } gctx.appliedEdges[ks] = struct{}{} } - *ea = append(*ea, ea2...) + *ea = append(*ea, e) } } } @@ -1348,11 +1355,8 @@ func (m *Map) AST() d2ast.Node { if m == nil { return nil } - astMap := &d2ast.Map{} - if m.Root() { - astMap.Range = d2ast.MakeRange(",0:0:0-1:0:0") - } else { - astMap.Range = d2ast.MakeRange(",1:0:0-2:0:0") + astMap := &d2ast.Map{ + Range: d2ast.MakeRange(",0:0:0-1:0:0"), } for _, f := range m.Fields { astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(f.AST().(d2ast.MapNode))) diff --git a/d2ir/filter_test.go b/d2ir/filter_test.go index 63375b816..06e926416 100644 --- a/d2ir/filter_test.go +++ b/d2ir/filter_test.go @@ -150,6 +150,21 @@ x -> y assertQuery(t, m, 0, 0, 0.1, "(x -> y)[1].style.opacity") }, }, + { + name: "label-filter/3", + run: func(t testing.TB) { + m, err := compile(t, ` +(* -> *)[*]: { + &label: hi + style.opacity: 0.1 +} + +x -> y: hi +`) + assert.Success(t, err) + assertQuery(t, m, 0, 0, 0.1, "(x -> y)[0].style.opacity") + }, + }, { name: "lazy-filter", run: func(t testing.TB) { diff --git a/d2ir/import.go b/d2ir/import.go index b933298dd..c415cf138 100644 --- a/d2ir/import.go +++ b/d2ir/import.go @@ -82,16 +82,11 @@ func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) { // Only get immediate imports. if len(c.importStack) == 2 { - if _, ok := c.importCache[impPath]; !ok { + if _, ok := c.seenImports[impPath]; !ok { c.imports = append(c.imports, imp.PathWithPre()) } } - ir, ok := c.importCache[impPath] - if ok { - return ir, true - } - var f fs.File var err error if c.fs == nil { @@ -113,13 +108,13 @@ func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) { return nil, false } - ir = &Map{} + ir := &Map{} ir.initRoot() ir.parent.(*Field).References[0].Context_.Scope = ast c.compileMap(ir, ast, ast) - c.importCache[impPath] = ir + c.seenImports[impPath] = struct{}{} return ir, true } diff --git a/d2ir/import_test.go b/d2ir/import_test.go index 81a3e3f50..d67f5950d 100644 --- a/d2ir/import_test.go +++ b/d2ir/import_test.go @@ -232,7 +232,7 @@ label: meow`, _, err := compileFS(t, "index.d2", map[string]string{ "index.d2": "...@'./../x.d2'", }) - assert.ErrorString(t, err, `index.d2:1:1: failed to import "../x.d2": stat ../x.d2: invalid argument`) + assert.ErrorString(t, err, `index.d2:1:1: failed to import "../x.d2": open ../x.d2: invalid argument`) }, }, { diff --git a/d2ir/pattern_test.go b/d2ir/pattern_test.go index 941db0785..8cc32c6cf 100644 --- a/d2ir/pattern_test.go +++ b/d2ir/pattern_test.go @@ -310,6 +310,79 @@ layers.x: { wrapper.p } assertQuery(t, m, 0, 0, nil, "layers.x.wrapper.p") }, }, + { + name: "edge-glob-null", + run: func(t testing.TB) { + m, err := compile(t, `a -> b +(* -> *)[*]: null +x -> y +`) + assert.Success(t, err) + // 4 fields and 0 edges + assertQuery(t, m, 4, 0, nil, "") + }, + }, + { + name: "field-glob-style-inherit", + run: func(t testing.TB) { + m, err := compile(t, `*.style.opacity: 0 +x: { + style.opacity: 1 +} + +scenarios: { + 1: { + x + } +} +`) + assert.Success(t, err) + assertQuery(t, m, 0, 0, 1, "x.style.opacity") + assertQuery(t, m, 0, 0, 1, "scenarios.1.x.style.opacity") + }, + }, + { + name: "edge-glob-style-inherit/1", + run: func(t testing.TB) { + m, err := compile(t, `(* -> *)[*].style.opacity: 0 +x -> y: { + style.opacity: 1 +} + +scenarios: { + 1: { + x + } +} +`) + assert.Success(t, err) + assertQuery(t, m, 0, 0, 1, "(x -> y)[0].style.opacity") + assertQuery(t, m, 0, 0, 1, "scenarios.1.(x -> y)[0].style.opacity") + }, + }, + { + name: "edge-glob-style-inherit/2", + run: func(t testing.TB) { + m, err := compile(t, `*.style.opacity: 0 +(* -> *)[*].style.opacity: 0 +x -> y + +steps: { + 1: { + x.style.opacity: 1 + } + 2: { + (x -> y)[0].style.opacity: 1 + } + 3: { + y.style.opacity: 1 + } +} +`) + assert.Success(t, err) + assertQuery(t, m, 0, 0, 1, "steps.3.(x -> y)[0].style.opacity") + }, + }, { name: "double-glob/edge/1", run: func(t testing.TB) { diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index b367e404c..59c477403 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -570,6 +570,13 @@ func positionLabelsIcons(obj *d2graph.Object) { } else { obj.LabelPosition = go2.Pointer(label.InsideMiddleCenter.String()) } + if float64(obj.LabelDimensions.Width) > obj.Width || float64(obj.LabelDimensions.Height) > obj.Height { + if len(obj.ChildrenArray) > 0 { + obj.LabelPosition = go2.Pointer(label.OutsideTopCenter.String()) + } else { + obj.LabelPosition = go2.Pointer(label.OutsideBottomCenter.String()) + } + } } } diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index 2c0b45a9f..6d4c335f1 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -1148,5 +1148,12 @@ func positionLabelsIcons(obj *d2graph.Object) { } else { obj.LabelPosition = go2.Pointer(label.InsideMiddleCenter.String()) } + if float64(obj.LabelDimensions.Width) > obj.Width || float64(obj.LabelDimensions.Height) > obj.Height { + if len(obj.ChildrenArray) > 0 { + obj.LabelPosition = go2.Pointer(label.OutsideTopCenter.String()) + } else { + obj.LabelPosition = go2.Pointer(label.OutsideBottomCenter.String()) + } + } } } diff --git a/d2oracle/edit.go b/d2oracle/edit.go index 076e5d6ea..cc84983d9 100644 --- a/d2oracle/edit.go +++ b/d2oracle/edit.go @@ -199,7 +199,7 @@ func ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey, refs := edge.References if baseAST != g.AST { - refs = getWriteableEdgeRefs(edge, baseAST) + refs = GetWriteableEdgeRefs(edge, baseAST) if len(refs) == 0 || refs[0].ScopeAST != baseAST { // TODO null return nil, OutsideScopeError{} @@ -383,11 +383,11 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) break } obj = o - imported = IsImported(baseAST, obj) + imported = IsImportedObj(baseAST, obj) var maybeNewScope *d2ast.Map if baseAST != g.AST || imported { - writeableRefs := getWriteableRefs(obj, baseAST) + writeableRefs := GetWriteableRefs(obj, baseAST) for _, ref := range writeableRefs { if ref.MapKey != nil && ref.MapKey.Value.Map != nil { maybeNewScope = ref.MapKey.Value.Map @@ -414,7 +414,7 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) writeableLabelMK := true var objK *d2ast.Key if baseAST != g.AST || imported { - writeableRefs := getWriteableRefs(obj, baseAST) + writeableRefs := GetWriteableRefs(obj, baseAST) if len(writeableRefs) > 0 { objK = writeableRefs[0].MapKey } @@ -429,6 +429,19 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) break } } + } else { + // Even if not imported or different board, a label can be not writeable if it's in a class or var or glob + // In those cases, the label is not a direct object reference + found := false + for _, ref := range obj.References { + if ref.MapKey == obj.Label.MapKey { + found = true + break + } + } + if !found { + writeableLabelMK = false + } } var m *d2ast.Map if objK != nil { @@ -481,12 +494,17 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) if !ok { return errors.New("edge not found") } + imported = IsImportedEdge(baseAST, edge) refs := edge.References - if baseAST != g.AST { - refs = getWriteableEdgeRefs(edge, baseAST) + if baseAST != g.AST || imported { + refs = GetWriteableEdgeRefs(edge, baseAST) } onlyInChain := true - for _, ref := range refs { + var earliestRef *d2graph.EdgeReference + for i, ref := range refs { + if earliestRef == nil || ref.MapKey.Range.Before(earliestRef.MapKey.Range) { + earliestRef = &refs[i] + } // TODO merge flat edgekeys // E.g. this can group into a map // (y -> z)[0].style.opacity: 0.4 @@ -496,20 +514,31 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) onlyInChain = false } } - // If a ref has an exact match on this key, just change the value - tmp1 := *ref.MapKey - tmp2 := *mk - noVal1 := &tmp1 - noVal2 := &tmp2 - noVal1.Value = d2ast.ValueBox{} - noVal2.Value = d2ast.ValueBox{} - if noVal1.D2OracleEquals(noVal2) { - ref.MapKey.Value = mk.Value - return nil + + if ref.MapKey.EdgeIndex == nil || !ref.MapKey.EdgeIndex.Glob { + // If a ref has an exact match on this key, just change the value + tmp1 := *ref.MapKey + tmp2 := *mk + noVal1 := &tmp1 + noVal2 := &tmp2 + noVal1.Value = d2ast.ValueBox{} + noVal2.Value = d2ast.ValueBox{} + if noVal1.D2OracleEquals(noVal2) { + ref.MapKey.Value = mk.Value + return nil + } } } if onlyInChain { - appendMapKey(scope, mk) + if earliestRef != nil && scope.Range.Before(earliestRef.MapKey.Range) { + // Since the original mk was trimmed to common, we set to the edge that + // the ref's scope is in + mk.Edges[0] = earliestRef.Edge + // We can't reference an edge before it's been defined + earliestRef.Scope.InsertAfter(earliestRef.MapKey, mk) + } else { + appendMapKey(scope, mk) + } return nil } attrs = edge.Attributes @@ -533,7 +562,7 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) foundMap = true scope = ref.MapKey.Value.Map for _, n := range scope.Nodes { - if n.MapKey.Value.Map == nil { + if n.MapKey == nil || n.MapKey.Value.Map == nil { continue } if n.MapKey.Key == nil || len(n.MapKey.Key.Path) != 1 { @@ -574,6 +603,10 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) if s.MapKey.Range.Path != baseAST.Range.Path { return false } + // Globs are also not writeable + if s.MapKey.HasGlob() { + return false + } } return s != nil && s.MapKey != nil && !ir.InClass(s.MapKey) } @@ -646,14 +679,20 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) case "source-arrowhead", "target-arrowhead": var arrowhead *d2graph.Attributes if reservedKey == "source-arrowhead" { + if edge.SrcArrowhead != nil { + attrs = *edge.SrcArrowhead + } arrowhead = edge.SrcArrowhead } else { + if edge.DstArrowhead != nil { + attrs = *edge.DstArrowhead + } arrowhead = edge.DstArrowhead } if arrowhead != nil { if reservedTargetKey == "" { - if len(mk.Key.Path[reservedIndex:]) != 2 { - return errors.New("malformed style setting, expected 2 part path") + if len(mk.Key.Path[reservedIndex:]) < 2 { + return errors.New("malformed style setting, expected >= 2 part path") } reservedTargetKey = mk.Key.Path[reservedIndex+1].Unbox().ScalarString() } @@ -668,6 +707,12 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) arrowhead.Label.MapKey.SetScalar(mk.Value.ScalarBox()) return nil } + case "style": + reservedTargetKey = mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString() + if inlined(attrs.Style.Filled) { + attrs.Style.Filled.MapKey.SetScalar(mk.Value.ScalarBox()) + return nil + } } } case "style": @@ -770,9 +815,20 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) } } case "label": - if inlined(&attrs.Label) { - attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox()) - return nil + if len(mk.Key.Path[reservedIndex:]) > 1 { + reservedTargetKey = mk.Key.Path[reservedIndex+1].Unbox().ScalarString() + switch reservedTargetKey { + case "near": + if inlined(attrs.LabelPosition) { + attrs.LabelPosition.MapKey.SetScalar(mk.Value.ScalarBox()) + return nil + } + } + } else { + if inlined(&attrs.Label) { + attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox()) + return nil + } } } } @@ -846,7 +902,7 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, baseAST = boardG.BaseAST } - g2, err := deleteReserved(g, mk) + g2, err := deleteReserved(g, boardPath, baseAST, mk) if err != nil { return nil, err } @@ -868,45 +924,55 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, return g, nil } - refs := e.References - if len(boardPath) > 0 { - refs := getWriteableEdgeRefs(e, baseAST) - if len(refs) != len(e.References) { - mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) - } - } + imported := IsImportedEdge(baseAST, e) - if _, ok := mk.Value.Unbox().(*d2ast.Null); !ok { - ref := refs[0] - var refEdges []*d2ast.Edge - for _, ref := range refs { - refEdges = append(refEdges, ref.Edge) - } - ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Src, true) - ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Dst, false) - - for i := len(e.References) - 1; i >= 0; i-- { - ref := e.References[i] - deleteEdge(g, ref.Scope, ref.MapKey, ref.MapKeyEdgeIndex) + if imported { + mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) + appendMapKey(baseAST, mk) + } else { + refs := e.References + if len(boardPath) > 0 { + refs := GetWriteableEdgeRefs(e, baseAST) + if len(refs) != len(e.References) { + mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) + } } - edges, ok := obj.FindEdges(mk) - if ok { - for _, e2 := range edges { - if e2.Index <= e.Index { - continue + if _, ok := mk.Value.Unbox().(*d2ast.Null); !ok { + ref := refs[0] + var refEdges []*d2ast.Edge + for _, ref := range refs { + refEdges = append(refEdges, ref.Edge) + } + ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Src, true) + ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Dst, false) + + for i := len(e.References) - 1; i >= 0; i-- { + ref := e.References[i] + // Leave glob setters alone + if !(ref.MapKey.EdgeIndex != nil && ref.MapKey.EdgeIndex.Glob) { + deleteEdge(g, ref.Scope, ref.MapKey, ref.MapKeyEdgeIndex) } - for i := len(e2.References) - 1; i >= 0; i-- { - ref := e2.References[i] - if ref.MapKey.EdgeIndex != nil { - *ref.MapKey.EdgeIndex.Int-- + } + + edges, ok := obj.FindEdges(mk) + if ok { + for _, e2 := range edges { + if e2.Index <= e.Index { + continue + } + for i := len(e2.References) - 1; i >= 0; i-- { + ref := e2.References[i] + if ref.MapKey.EdgeIndex != nil { + *ref.MapKey.EdgeIndex.Int-- + } } } } + } else { + // NOTE: it only needs to be after the last ref, but perhaps simplest and cleanest to append all nulls at the end + appendMapKey(baseAST, mk) } - } else { - // NOTE: it only needs to be after the last ref, but perhaps simplest and cleanest to append all nulls at the end - appendMapKey(baseAST, mk) } if len(boardPath) > 0 { replaced := ReplaceBoardNode(g.AST, baseAST, boardPath) @@ -918,17 +984,19 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, return recompile(boardG) } - prevG, _ := recompile(boardG) + prevG, err := recompile(boardG) + if err != nil { + return nil, err + } obj, ok := boardG.Root.HasChild(d2graph.Key(mk.Key)) if !ok { return g, nil } - imported := IsImported(baseAST, obj) + imported := IsImportedObj(baseAST, obj) if imported { - println(d2format.Format(boardG.AST)) mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) appendMapKey(baseAST, mk) } else { @@ -941,7 +1009,7 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, return g, nil } if len(boardPath) > 0 { - writeableRefs := getWriteableRefs(obj, baseAST) + writeableRefs := GetWriteableRefs(obj, baseAST) if len(writeableRefs) != len(obj.References) { mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) } @@ -997,7 +1065,7 @@ func bumpChildrenUnderscores(m *d2ast.Map) { } func hoistRefChildren(g *d2graph.Graph, key *d2ast.KeyPath, ref d2graph.Reference) { - if ref.MapKey.Value.Map == nil { + if ref.MapKey == nil || ref.MapKey.Value.Map == nil { return } @@ -1053,7 +1121,7 @@ func renameConflictsToParent(g *d2graph.Graph, key *d2ast.KeyPath) (*d2graph.Gra var absKeys []*d2ast.KeyPath if len(ref.Key.Path)-1 == ref.KeyPathIndex { - if ref.MapKey.Value.Map == nil { + if ref.MapKey == nil || ref.MapKey.Value.Map == nil { continue } var mapKeys []*d2ast.KeyPath @@ -1178,7 +1246,7 @@ func renameConflictsToParent(g *d2graph.Graph, key *d2ast.KeyPath) (*d2graph.Gra return g, nil } -func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) { +func deleteReserved(g *d2graph.Graph, boardPath []string, baseAST *d2ast.Map, mk *d2ast.Key) (*d2graph.Graph, error) { targetKey := mk.Key if len(mk.Edges) == 1 { if mk.EdgeKey == nil { @@ -1193,10 +1261,17 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) { var e *d2graph.Edge obj := g.Root + if len(boardPath) > 0 { + boardG := GetBoardGraph(g, boardPath) + if boardG == nil { + return nil, fmt.Errorf("board %v not found", boardPath) + } + obj = boardG.Root + } if len(mk.Edges) == 1 { if mk.Key != nil { var ok bool - obj, ok = g.Root.HasChild(d2graph.Key(mk.Key)) + obj, ok = obj.HasChild(d2graph.Key(mk.Key)) if !ok { return g, nil } @@ -1205,26 +1280,45 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) { if !ok { return g, nil } + imported := IsImportedEdge(baseAST, e) - if err := deleteEdgeField(g, e, targetKey.Path[len(targetKey.Path)-1].Unbox().ScalarString()); err != nil { + deleted, err := deleteEdgeField(g, baseAST, e, targetKey.Path[len(targetKey.Path)-1].Unbox().ScalarString()) + if err != nil { return nil, err } + if !deleted && imported { + mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) + appendMapKey(baseAST, mk) + } return recompile(g) } - isStyleKey := false - for _, id := range d2graph.Key(targetKey) { + isNestedKey := false + imported := false + parts := d2graph.Key(targetKey) + for i, id := range parts { _, ok := d2graph.ReservedKeywords[id] if ok { if id == "style" { - isStyleKey = true + isNestedKey = true continue } - if isStyleKey { - err := deleteObjField(g, obj, id) + if id == "label" || id == "icon" { + if i < len(parts)-1 { + isNestedKey = true + continue + } + } + if isNestedKey { + deleted, err := deleteObjField(g, baseAST, obj, id) if err != nil { return nil, err } + if !deleted && imported { + mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) + appendMapKey(baseAST, mk) + } + continue } if id == "near" || @@ -1235,10 +1329,15 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) { id == "left" || id == "top" || id == "link" { - err := deleteObjField(g, obj, id) + deleted, err := deleteObjField(g, baseAST, obj, id) if err != nil { return nil, err } + if !deleted && imported { + mk.Value = d2ast.MakeValueBox(&d2ast.Null{}) + appendMapKey(baseAST, mk) + } else { + } } break } @@ -1246,59 +1345,84 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) { if !ok { return nil, fmt.Errorf("object not found") } + imported = IsImportedObj(baseAST, obj) } return recompile(g) } -func deleteMapField(m *d2ast.Map, field string) { +func deleteMapField(m *d2ast.Map, field string) (deleted bool) { for i := 0; i < len(m.Nodes); i++ { n := m.Nodes[i] if n.MapKey != nil && n.MapKey.Key != nil { if n.MapKey.Key.Path[0].Unbox().ScalarString() == field { deleteFromMap(m, n.MapKey) } else if n.MapKey.Key.Path[0].Unbox().ScalarString() == "style" || + n.MapKey.Key.Path[0].Unbox().ScalarString() == "label" || + n.MapKey.Key.Path[0].Unbox().ScalarString() == "icon" || n.MapKey.Key.Path[0].Unbox().ScalarString() == "source-arrowhead" || n.MapKey.Key.Path[0].Unbox().ScalarString() == "target-arrowhead" { if n.MapKey.Value.Map != nil { - deleteMapField(n.MapKey.Value.Map, field) + deleted2 := deleteMapField(n.MapKey.Value.Map, field) + if deleted2 { + deleted = true + } if len(n.MapKey.Value.Map.Nodes) == 0 { - deleteFromMap(m, n.MapKey) + deleted2 := deleteFromMap(m, n.MapKey) + if deleted2 { + deleted = true + } } } else if len(n.MapKey.Key.Path) == 2 && n.MapKey.Key.Path[1].Unbox().ScalarString() == field { - deleteFromMap(m, n.MapKey) + deleted2 := deleteFromMap(m, n.MapKey) + if deleted2 { + deleted = true + } } } } } + return deleted } -func deleteEdgeField(g *d2graph.Graph, e *d2graph.Edge, field string) error { +func deleteEdgeField(g *d2graph.Graph, ast *d2ast.Map, e *d2graph.Edge, field string) (deleted bool, _ error) { for _, ref := range e.References { // Edge chains can't have fields if len(ref.MapKey.Edges) > 1 { continue } + if ref.MapKey.Range.Path != ast.Range.Path { + continue + } if ref.MapKey.Value.Map != nil { - deleteMapField(ref.MapKey.Value.Map, field) + deleted2 := deleteMapField(ref.MapKey.Value.Map, field) + if deleted2 { + deleted = true + } } else if ref.MapKey.EdgeKey != nil && ref.MapKey.EdgeKey.Path[len(ref.MapKey.EdgeKey.Path)-1].Unbox().ScalarString() == field { // It's always safe to delete, since edge references must coexist with edge definition elsewhere - deleteFromMap(ref.Scope, ref.MapKey) + deleted2 := deleteFromMap(ref.Scope, ref.MapKey) + if deleted2 { + deleted = true + } } } - return nil + return deleted, nil } -func deleteObjField(g *d2graph.Graph, obj *d2graph.Object, field string) error { +func deleteObjField(g *d2graph.Graph, ast *d2ast.Map, obj *d2graph.Object, field string) (deleted bool, _ error) { objK, err := d2parser.ParseKey(obj.AbsID()) if err != nil { - return err + return false, err } objGK := d2graph.Key(objK) for _, ref := range obj.References { if ref.InEdge() { continue } + if ref.Key.Range.Path != ast.Range.Path { + continue + } if ref.MapKey.Value.Map != nil { deleteMapField(ref.MapKey.Value.Map, field) } else if (len(ref.Key.Path) >= 2 && @@ -1306,15 +1430,20 @@ func deleteObjField(g *d2graph.Graph, obj *d2graph.Object, field string) error { ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == obj.ID) || (len(ref.Key.Path) >= 3 && ref.Key.Path[len(ref.Key.Path)-1].Unbox().ScalarString() == field && - ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == "style" && + (ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == "style" || + ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == "label" || + ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == "icon") && ref.Key.Path[len(ref.Key.Path)-3].Unbox().ScalarString() == obj.ID) { tmpNodes := make([]d2ast.MapNodeBox, len(ref.Scope.Nodes)) copy(tmpNodes, ref.Scope.Nodes) // If I delete this, will the object still exist? - deleteFromMap(ref.Scope, ref.MapKey) + deleted2 := deleteFromMap(ref.Scope, ref.MapKey) + if deleted2 { + deleted = true + } g2, err := recompile(g) if err != nil { - return err + return false, err } if _, ok := g2.Root.HasChild(objGK); !ok { // Nope, so can't delete it, just remove the field then @@ -1325,7 +1454,7 @@ func deleteObjField(g *d2graph.Graph, obj *d2graph.Object, field string) error { } } - return nil + return deleted, nil } func deleteObject(g *d2graph.Graph, baseAST *d2ast.Map, key *d2ast.KeyPath, obj *d2graph.Object) (*d2graph.Graph, error) { @@ -1635,7 +1764,10 @@ func move(g *d2graph.Graph, boardPath []string, key, newKey string, includeDesce return recompile(g) } - prevG, _ := recompile(boardG) + prevG, err := recompile(boardG) + if err != nil { + return nil, err + } ak := d2graph.Key(mk.Key) ak2 := d2graph.Key(mk2.Key) @@ -1655,7 +1787,7 @@ func move(g *d2graph.Graph, boardPath []string, key, newKey string, includeDesce } if len(boardPath) > 0 { - writeableRefs := getWriteableRefs(obj, baseAST) + writeableRefs := GetWriteableRefs(obj, baseAST) if len(writeableRefs) != len(obj.References) { return nil, OutsideScopeError{} } @@ -2159,8 +2291,17 @@ func updateNear(prevG, g *d2graph.Graph, from, to *string, includeDescendants bo if len(n.MapKey.Key.Path) == 0 { continue } + if len(n.MapKey.Key.Path) > 1 { + if n.MapKey.Key.Path[len(n.MapKey.Key.Path)-2].Unbox().ScalarString() == "label" || + n.MapKey.Key.Path[len(n.MapKey.Key.Path)-2].Unbox().ScalarString() == "icon" { + continue + } + } if n.MapKey.Key.Path[len(n.MapKey.Key.Path)-1].Unbox().ScalarString() == "near" { k := n.MapKey.Value.ScalarBox().Unbox().ScalarString() + if _, ok := d2graph.NearConstants[k]; ok { + continue + } if strings.EqualFold(k, *from) && to == nil { deleteFromMap(obj.Map, n.MapKey) } else { @@ -3122,21 +3263,3 @@ func filterReservedPath(path []*d2ast.StringBox) (filtered []*d2ast.StringBox) { } return } - -func getWriteableRefs(obj *d2graph.Object, writeableAST *d2ast.Map) (out []d2graph.Reference) { - for i, ref := range obj.References { - if ref.ScopeAST == writeableAST && ref.Key.Range.Path == writeableAST.Range.Path { - out = append(out, obj.References[i]) - } - } - return -} - -func getWriteableEdgeRefs(edge *d2graph.Edge, writeableAST *d2ast.Map) (out []d2graph.EdgeReference) { - for i, ref := range edge.References { - if ref.ScopeAST == writeableAST { - out = append(out, edge.References[i]) - } - } - return -} diff --git a/d2oracle/edit_test.go b/d2oracle/edit_test.go index 198cc83dc..bbab7f2e8 100644 --- a/d2oracle/edit_test.go +++ b/d2oracle/edit_test.go @@ -1177,6 +1177,83 @@ b } } b: {style.fill: green} +`, + }, + { + name: "class-with-label", + text: `classes: { + user: { + label: "" + } +} + +a.class: user +`, + key: `a.style.opacity`, + value: go2.Pointer(`0.5`), + exp: `classes: { + user: { + label: "" + } +} + +a.class: user +a.style.opacity: 0.5 +`, + }, + { + name: "edge-class-with-label", + text: `classes: { + user: { + label: "" + } +} + +a -> b: { + class: user +} +`, + key: `(a -> b)[0].style.opacity`, + value: go2.Pointer(`0.5`), + exp: `classes: { + user: { + label: "" + } +} + +a -> b: { + class: user + style.opacity: 0.5 +} +`, + }, + { + name: "var-with-label", + text: `vars: { + user: "" +} + +a: ${user} +`, + key: `a.style.opacity`, + value: go2.Pointer(`0.5`), + exp: `vars: { + user: "" +} + +a: ${user} {style.opacity: 0.5} +`, + }, + { + name: "glob-with-label", + text: `*.label: "" +a +`, + key: `a.style.opacity`, + value: go2.Pointer(`0.5`), + exp: `*.label: "" +a +a.style.opacity: 0.5 `, }, { @@ -1518,6 +1595,86 @@ a.b -> a.c: {style.animated: true} value: go2.Pointer(`diamond`), exp: `x -> y: {target-arrowhead.shape: diamond} +`, + }, + { + name: "edge-arrowhead-filled/1", + text: `x -> y +`, + key: `(x -> y)[0].target-arrowhead.style.filled`, + value: go2.Pointer(`true`), + + exp: `x -> y: {target-arrowhead.style.filled: true} +`, + }, + { + name: "edge-arrowhead-filled/2", + text: `x -> y: { + target-arrowhead: * { + shape: diamond + } +} +`, + key: `(x -> y)[0].target-arrowhead.style.filled`, + value: go2.Pointer(`true`), + + exp: `x -> y: { + target-arrowhead: * { + shape: diamond + style.filled: true + } +} +`, + }, + { + name: "edge-arrowhead-filled/3", + text: `x -> y: { + target-arrowhead.shape: diamond +} +`, + key: `(x -> y)[0].target-arrowhead.style.filled`, + value: go2.Pointer(`true`), + + exp: `x -> y: { + target-arrowhead.shape: diamond + target-arrowhead.style.filled: true +} +`, + }, + { + name: "edge-arrowhead-filled/4", + text: `x -> y: { + target-arrowhead.shape: diamond + target-arrowhead.style.filled: true +} +`, + key: `(x -> y)[0].target-arrowhead.style.filled`, + value: go2.Pointer(`false`), + + exp: `x -> y: { + target-arrowhead.shape: diamond + target-arrowhead.style.filled: false +} +`, + }, + { + name: "edge-arrowhead-filled/5", + text: `x -> y: { + target-arrowhead.shape: diamond + target-arrowhead.style: { + filled: false + } +} +`, + key: `(x -> y)[0].target-arrowhead.style.filled`, + value: go2.Pointer(`true`), + + exp: `x -> y: { + target-arrowhead.shape: diamond + target-arrowhead.style: { + filled: true + } +} `, }, { @@ -2171,6 +2328,252 @@ layers: { b.style.fill: red } } +`, + }, + { + name: "import/9", + + text: `...@yo +`, + fsTexts: map[string]string{ + "yo.d2": `a -> b`, + }, + key: `(a -> b)[0].style.stroke`, + value: go2.Pointer(`red`), + exp: `...@yo +(a -> b)[0].style.stroke: red +`, + }, + { + name: "label-near/1", + + text: `x +`, + key: `x.label.near`, + value: go2.Pointer(`bottom-right`), + exp: `x: {label.near: bottom-right} +`, + }, + { + name: "label-near/2", + + text: `x.label.near: bottom-left +`, + key: `x.label.near`, + value: go2.Pointer(`bottom-right`), + exp: `x.label.near: bottom-right +`, + }, + { + name: "label-near/3", + + text: `x: { + label.near: bottom-left +} +`, + key: `x.label.near`, + value: go2.Pointer(`bottom-right`), + exp: `x: { + label.near: bottom-right +} +`, + }, + { + name: "label-near/4", + + text: `x: { + label: hi { + near: bottom-left + } +} +`, + key: `x.label.near`, + value: go2.Pointer(`bottom-right`), + exp: `x: { + label: hi { + near: bottom-right + } +} +`, + }, + { + name: "label-near/5", + + text: `x: hi { + label: { + near: bottom-left + } +} +`, + key: `x.label.near`, + value: go2.Pointer(`bottom-right`), + exp: `x: hi { + label: { + near: bottom-right + } +} +`, + }, + { + name: "glob-field/1", + + text: `*.style.fill: red +a +b +`, + key: `a.style.fill`, + value: go2.Pointer(`blue`), + exp: `*.style.fill: red +a: {style.fill: blue} +b +`, + }, + { + name: "glob-field/2", + + text: `(* -> *)[*].style.stroke: red +a -> b +a -> b +`, + key: `(a -> b)[0].style.stroke`, + value: go2.Pointer(`blue`), + exp: `(* -> *)[*].style.stroke: red +a -> b: {style.stroke: blue} +a -> b +`, + }, + { + name: "glob-field/3", + + text: `(* -> *)[*].style.stroke: red +a -> b: {style.stroke: blue} +a -> b +`, + key: `(a -> b)[0].style.stroke`, + value: go2.Pointer(`green`), + exp: `(* -> *)[*].style.stroke: red +a -> b: {style.stroke: green} +a -> b +`, + }, + { + name: "nested-edge-chained/1", + + text: `a: { + b: { + c + } +} + +x -> a.b -> a.b.c +`, + key: `(a.b -> a.b.c)[0].style.stroke`, + value: go2.Pointer(`green`), + exp: `a: { + b: { + c + } +} + +x -> a.b -> a.b.c +(a.b -> a.b.c)[0].style.stroke: green +`, + }, + { + name: "nested-edge-chained/2", + + text: `z: { + a: { + b: { + c + } + } + x -> a.b -> a.b.c +} +`, + key: `(z.a.b -> z.a.b.c)[0].style.stroke`, + value: go2.Pointer(`green`), + exp: `z: { + a: { + b: { + c + } + } + x -> a.b -> a.b.c + (a.b -> a.b.c)[0].style.stroke: green +} +`, + }, + { + name: "edge-comment", + + text: `x -> y: { + # hi + style.stroke: blue +} +`, + key: `(x -> y)[0].style.stroke`, + value: go2.Pointer(`green`), + exp: `x -> y: { + # hi + style.stroke: green +} +`, + }, + { + name: "scenario-child", + + text: `a -> b + +scenarios: { + x: { + hi + } +} +`, + key: `(a -> b)[0].style.stroke-width`, + value: go2.Pointer(`3`), + boardPath: []string{"x"}, + exp: `a -> b + +scenarios: { + x: { + hi + (a -> b)[0].style.stroke-width: 3 + } +} +`, + }, + { + name: "scenario-grandchild", + + text: `a -> b + +scenarios: { + x: { + scenarios: { + c: { + (a -> b)[0].style.bold: true + } + } + } +} + `, + key: `(a -> b)[0].style.stroke-width`, + value: go2.Pointer(`3`), + boardPath: []string{"x", "c"}, + exp: `a -> b + +scenarios: { + x: { + scenarios: { + c: { + (a -> b)[0].style.bold: true + (a -> b)[0].style.stroke-width: 3 + } + } + } +} `, }, } @@ -7205,6 +7608,305 @@ scenarios: { x: null } } +`, + }, + { + name: "import/3", + + text: `...@meow +`, + fsTexts: map[string]string{ + "meow.d2": `a -> b +`, + }, + key: `(a -> b)[0]`, + exp: `...@meow +(a -> b)[0]: null +`, + }, + { + name: "import/4", + + text: `...@meow +`, + fsTexts: map[string]string{ + "meow.d2": `a.link: https://google.com +`, + }, + key: `a.link`, + exp: `...@meow +a.link: null +`, + }, + { + name: "import/5", + + text: `...@meow +`, + fsTexts: map[string]string{ + "meow.d2": `a -> b: { + target-arrowhead: 1 +} +`, + }, + key: `(a -> b)[0].target-arrowhead`, + exp: `...@meow +(a -> b)[0].target-arrowhead: null +`, + }, + { + name: "import/6", + + text: `...@meow +`, + fsTexts: map[string]string{ + "meow.d2": `a.style.fill: red +`, + }, + key: `a.style.fill`, + exp: `...@meow +a.style.fill: null +`, + }, + { + name: "import/7", + + text: `...@meow +a.label.near: center-center +`, + fsTexts: map[string]string{ + "meow.d2": `a +`, + }, + key: `a.label.near`, + exp: `...@meow +`, + }, + { + name: "import/8", + + text: `...@meow +(a -> b)[0].style.stroke: red +`, + fsTexts: map[string]string{ + "meow.d2": `a -> b +`, + }, + key: `(a -> b)[0].style.stroke`, + exp: `...@meow +`, + }, + { + name: "label-near/1", + + text: `yes: {label.near: center-center} +`, + key: `yes.label.near`, + exp: `yes +`, + }, + { + name: "label-near/2", + + text: `yes.label.near: center-center +`, + key: `yes.label.near`, + exp: `yes +`, + }, + { + name: "connection-glob", + + text: `* -> * +a +b +`, + key: `(a -> b)[0]`, + exp: `* -> * +a +b +(a -> b)[0]: null +`, + }, + { + name: "glob-child/1", + + text: `*.b +a +`, + key: `a.b`, + exp: `*.b +a +a.b: null +`, + }, + { + name: "delete-imported-layer-obj", + + text: `layers: { + x: { + ...@meow + } +} +`, + fsTexts: map[string]string{ + "meow.d2": `a +`, + }, + boardPath: []string{"x"}, + key: `a`, + exp: `layers: { + x: { + ...@meow + a: null + } +} +`, + }, + { + name: "delete-not-layer-obj", + + text: `b.style.fill: red +layers: { + x: { + a + } +} +`, + key: `b.style.fill`, + exp: `b + +layers: { + x: { + a + } +} +`, + }, + { + name: "delete-layer-obj", + + text: `layers: { + x: { + a + } +} +`, + boardPath: []string{"x"}, + key: `a`, + exp: `layers: { + x +} +`, + }, + { + name: "delete-layer-style", + + text: `layers: { + x: { + a.style.fill: red + } +} +`, + boardPath: []string{"x"}, + key: `a.style.fill`, + exp: `layers: { + x: { + a + } +} +`, + }, + { + name: "edge-out-layer", + + text: `x: { + a -> b +} +`, + key: `x.(a -> b)[0].style.stroke`, + exp: `x: { + a -> b +} +`, + }, + { + name: "edge-in-layer", + + text: `layers: { + test: { + x: { + a -> b + } + } +} +`, + boardPath: []string{"test"}, + key: `x.(a -> b)[0].style.stroke`, + exp: `layers: { + test: { + x: { + a -> b + } + } +} +`, + }, + { + name: "label-near-in-layer", + + text: `layers: { + x: { + y: { + label.near: center-center + } + a + } +} +`, + boardPath: []string{"x"}, + key: `y`, + exp: `layers: { + x: { + a + } +} +`, + }, + { + name: "update-near-in-layer", + + text: `layers: { + x: { + y: { + near: a + } + a + } +} +`, + boardPath: []string{"x"}, + key: `y`, + exp: `layers: { + x: { + a + } +} +`, + }, + { + name: "edge-with-glob", + + text: `x -> y +y + +(* -> *)[*].style.opacity: 0.8 +`, + key: `(x -> y)[0]`, + exp: `x +y + +(* -> *)[*].style.opacity: 0.8 `, }, } diff --git a/d2oracle/get.go b/d2oracle/get.go index 6e5721ee8..3d3daf957 100644 --- a/d2oracle/get.go +++ b/d2oracle/get.go @@ -140,8 +140,11 @@ func GetParentID(g *d2graph.Graph, boardPath []string, absID string) (string, er return obj.Parent.AbsID(), nil } -func IsImported(ast *d2ast.Map, obj *d2graph.Object) bool { +func IsImportedObj(ast *d2ast.Map, obj *d2graph.Object) bool { for _, ref := range obj.References { + if ref.Key.HasGlob() { + return true + } if ref.Key.Range.Path != ast.Range.Path { return true } @@ -150,6 +153,22 @@ func IsImported(ast *d2ast.Map, obj *d2graph.Object) bool { return false } +// Glob creations count as imported for now +// TODO Probably rename later +func IsImportedEdge(ast *d2ast.Map, edge *d2graph.Edge) bool { + for _, ref := range edge.References { + // If edge index, the glob is just setting something, not responsible for creating the edge + if (ref.Edge.Src.HasGlob() || ref.Edge.Dst.HasGlob()) && ref.MapKey.EdgeIndex == nil { + return true + } + if ref.Edge.Range.Path != ast.Range.Path { + return true + } + } + + return false +} + func GetObj(g *d2graph.Graph, boardPath []string, absID string) *d2graph.Object { g = GetBoardGraph(g, boardPath) if g == nil { @@ -227,3 +246,21 @@ func GetID(key string) string { return d2format.Format(d2ast.RawString(mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString(), true)) } + +func GetWriteableRefs(obj *d2graph.Object, writeableAST *d2ast.Map) (out []d2graph.Reference) { + for i, ref := range obj.References { + if ref.ScopeAST == writeableAST && ref.Key.Range.Path == writeableAST.Range.Path { + out = append(out, obj.References[i]) + } + } + return +} + +func GetWriteableEdgeRefs(edge *d2graph.Edge, writeableAST *d2ast.Map) (out []d2graph.EdgeReference) { + for i, ref := range edge.References { + if ref.ScopeAST == writeableAST { + out = append(out, edge.References[i]) + } + } + return +} diff --git a/d2plugin/exec.go b/d2plugin/exec.go index 4631ef036..fd3856b11 100644 --- a/d2plugin/exec.go +++ b/d2plugin/exec.go @@ -201,3 +201,59 @@ func (p *execPlugin) PostProcess(ctx context.Context, in []byte) ([]byte, error) return stdout, nil } + +func (p *execPlugin) RouteEdges(ctx context.Context, g *d2graph.Graph, edges []*d2graph.Edge) error { + ctx, cancel := timelib.WithTimeout(ctx, time.Minute*2) + defer cancel() + + graphBytes, err := d2graph.SerializeGraph(g) + if err != nil { + return err + } + + var g2 d2graph.Graph + err = d2graph.DeserializeGraph(graphBytes, &g2) + if err != nil { + return fmt.Errorf("failed to unmarshal json: %w", err) + } + g2.Edges = edges + graphBytes2, err := d2graph.SerializeGraph(&g2) + if err != nil { + return err + } + + in := routeEdgesInput{ + G: graphBytes, + GEdges: graphBytes2, + } + + b, err := json.Marshal(in) + if err != nil { + return err + } + + args := []string{"routeedges"} + for k, v := range p.opts { + args = append(args, fmt.Sprintf("--%s", k), v) + } + cmd := exec.CommandContext(ctx, p.path, args...) + + buffer := bytes.Buffer{} + buffer.Write(b) + cmd.Stdin = &buffer + + stdout, err := cmd.Output() + if err != nil { + ee := &exec.ExitError{} + if errors.As(err, &ee) && len(ee.Stderr) > 0 { + return fmt.Errorf("%v\nstderr:\n%s", ee, ee.Stderr) + } + return err + } + err = d2graph.DeserializeGraph(stdout, g) + if err != nil { + return fmt.Errorf("failed to unmarshal json: %w", err) + } + + return nil +} diff --git a/d2plugin/plugin.go b/d2plugin/plugin.go index f12868faf..6708e5e03 100644 --- a/d2plugin/plugin.go +++ b/d2plugin/plugin.go @@ -85,6 +85,11 @@ type RoutingPlugin interface { RouteEdges(context.Context, *d2graph.Graph, []*d2graph.Edge) error } +type routeEdgesInput struct { + G []byte `json:"g"` + GEdges []byte `json:"gEdges"` +} + // PluginInfo is the current info information of a plugin. // note: The two fields Type and Path are not set by the plugin // itself but only in ListPlugins. diff --git a/d2plugin/serve.go b/d2plugin/serve.go index 9cae5ca2f..c975217ce 100644 --- a/d2plugin/serve.go +++ b/d2plugin/serve.go @@ -58,6 +58,12 @@ func Serve(p Plugin) xmain.RunFunc { return layout(ctx, p, ms) case "postprocess": return postProcess(ctx, p, ms) + case "routeedges": + routingPlugin, ok := p.(RoutingPlugin) + if !ok { + return fmt.Errorf("plugin has routing feature but does not implement RoutingPlugin") + } + return routeEdges(ctx, routingPlugin, ms) default: return xmain.UsageErrorf("unrecognized command: %s", subcmd) } @@ -137,3 +143,41 @@ func postProcess(ctx context.Context, p Plugin, ms *xmain.State) error { } return nil } + +func routeEdges(ctx context.Context, p RoutingPlugin, ms *xmain.State) error { + inRaw, err := io.ReadAll(ms.Stdin) + if err != nil { + return err + } + + var in routeEdgesInput + err = json.Unmarshal(inRaw, &in) + if err != nil { + return err + } + + var g d2graph.Graph + if err := d2graph.DeserializeGraph(in.G, &g); err != nil { + return fmt.Errorf("failed to unmarshal input graph to graph: %s", in) + } + + var gedges d2graph.Graph + if err := d2graph.DeserializeGraph(in.GEdges, &gedges); err != nil { + return fmt.Errorf("failed to unmarshal input edges graph to graph: %s", in) + } + + err = p.RouteEdges(ctx, &g, gedges.Edges) + if err != nil { + return err + } + + b, err := d2graph.SerializeGraph(&g) + if err != nil { + return err + } + _, err = ms.Stdout.Write(b) + if err != nil { + return err + } + return nil +} diff --git a/d2renderers/d2sketch/sketch.go b/d2renderers/d2sketch/sketch.go index 38918c88b..edb8f547c 100644 --- a/d2renderers/d2sketch/sketch.go +++ b/d2renderers/d2sketch/sketch.go @@ -321,29 +321,70 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) { } func Connection(r *Runner, connection d2target.Connection, path, attrs string) (string, error) { - roughness := 0.5 - js := fmt.Sprintf(`node = rc.path("%s", {roughness: %f, seed: 1});`, path, roughness) - paths, err := computeRoughPathData(r, js) - if err != nil { - return "", err - } - output := "" animatedClass := "" if connection.Animated { animatedClass = " animated-connection" } - pathEl := d2themes.NewThemableElement("path") - pathEl.Fill = color.None - pathEl.Stroke = connection.Stroke - pathEl.ClassName = fmt.Sprintf("connection%s", animatedClass) - pathEl.Style = connection.CSSStyle() - pathEl.Attributes = attrs - for _, p := range paths { - pathEl.D = p - output += pathEl.Render() + if connection.Animated { + // If connection is animated and bidirectional + if (connection.DstArrow == d2target.NoArrowhead && connection.SrcArrow == d2target.NoArrowhead) || (connection.DstArrow != d2target.NoArrowhead && connection.SrcArrow != d2target.NoArrowhead) { + // There is no pure CSS way to animate bidirectional connections in two directions, so we split it up + path1, path2, err := svg.SplitPath(path, 0.5) + + if err != nil { + return "", err + } + + pathEl1 := d2themes.NewThemableElement("path") + pathEl1.D = path1 + pathEl1.Fill = color.None + pathEl1.Stroke = connection.Stroke + pathEl1.ClassName = fmt.Sprintf("connection%s", animatedClass) + pathEl1.Style = connection.CSSStyle() + pathEl1.Style += "animation-direction: reverse;" + pathEl1.Attributes = attrs + + pathEl2 := d2themes.NewThemableElement("path") + pathEl2.D = path2 + pathEl2.Fill = color.None + pathEl2.Stroke = connection.Stroke + pathEl2.ClassName = fmt.Sprintf("connection%s", animatedClass) + pathEl2.Style = connection.CSSStyle() + pathEl2.Attributes = attrs + return pathEl1.Render() + " " + pathEl2.Render(), nil + } else { + pathEl := d2themes.NewThemableElement("path") + pathEl.D = path + pathEl.Fill = color.None + pathEl.Stroke = connection.Stroke + pathEl.ClassName = fmt.Sprintf("connection%s", animatedClass) + pathEl.Style = connection.CSSStyle() + pathEl.Attributes = attrs + return pathEl.Render(), nil + } + } else { + roughness := 0.5 + js := fmt.Sprintf(`node = rc.path("%s", {roughness: %f, seed: 1});`, path, roughness) + paths, err := computeRoughPathData(r, js) + if err != nil { + return "", err + } + + output := "" + + pathEl := d2themes.NewThemableElement("path") + pathEl.Fill = color.None + pathEl.Stroke = connection.Stroke + pathEl.ClassName = fmt.Sprintf("connection%s", animatedClass) + pathEl.Style = connection.CSSStyle() + pathEl.Attributes = attrs + for _, p := range paths { + pathEl.D = p + output += pathEl.Render() + } + return output, nil } - return output, nil } // TODO cleanup @@ -802,6 +843,13 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW stroke, BG_COLOR, ) + case d2target.CircleArrowhead: + arrowJS = fmt.Sprintf( + `node = rc.circle(-2, -1, 8, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 1, seed: 5 })`, + strokeWidth, + stroke, + BG_COLOR, + ) } return } diff --git a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg index 84ace1a20..c847c50bd 100644 --- a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg +++ b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg @@ -1,4 +1,4 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NETWORKUSERAPI SERVERLOGSCELL TOWERONLINE PORTALDATA PROCESSORSATELLITESTRANSMITTERUISTORAGE SENDSENDSENDPHONE LOGSMAKE CALL ACCESSDISPLAYPERSIST + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/syntax.png b/docs/assets/syntax.png deleted file mode 100644 index a836246ed..000000000 Binary files a/docs/assets/syntax.png and /dev/null differ diff --git a/e2etests-cli/main_test.go b/e2etests-cli/main_test.go index a47f2f819..5a2f925d7 100644 --- a/e2etests-cli/main_test.go +++ b/e2etests-cli/main_test.go @@ -765,6 +765,18 @@ i used to read assert.Testdata(t, ".svg", svg) }, }, + { + name: "theme-pdf", + skipCI: true, + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "in.d2", `x -> y`) + err := runTestMain(t, ctx, dir, env, "--theme=5", "in.d2", "out.pdf") + assert.Success(t, err) + + pdf := readFile(t, dir, "out.pdf") + testdataIgnoreDiff(t, ".pdf", pdf) + }, + }, { name: "renamed-board", skipCI: true, diff --git a/e2etests-cli/testdata/TestCLI_E2E/abspath.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/abspath.exp.svg index 4c6fec44b..e68e7efce 100644 --- a/e2etests-cli/testdata/TestCLI_E2E/abspath.exp.svg +++ b/e2etests-cli/testdata/TestCLI_E2E/abspath.exp.svg @@ -1,4 +1,4 @@ -โฌคCheck PINSearch NetworkReadyOffโฌคEnter PINโฌค /check PIN[pin invalid][pin OK][pin OK]network foundpower offpower offpower off - - - - - - - - - - - - - - - - - + .d2-2887586175 .fill-N1{fill:#0A0F25;} + .d2-2887586175 .fill-N2{fill:#676C7E;} + .d2-2887586175 .fill-N3{fill:#9499AB;} + .d2-2887586175 .fill-N4{fill:#CFD2DD;} + .d2-2887586175 .fill-N5{fill:#DEE1EB;} + .d2-2887586175 .fill-N6{fill:#EEF1F8;} + .d2-2887586175 .fill-N7{fill:#FFFFFF;} + .d2-2887586175 .fill-B1{fill:#0D32B2;} + .d2-2887586175 .fill-B2{fill:#0D32B2;} + .d2-2887586175 .fill-B3{fill:#E3E9FD;} + .d2-2887586175 .fill-B4{fill:#E3E9FD;} + .d2-2887586175 .fill-B5{fill:#EDF0FD;} + .d2-2887586175 .fill-B6{fill:#F7F8FE;} + .d2-2887586175 .fill-AA2{fill:#4A6FF3;} + .d2-2887586175 .fill-AA4{fill:#EDF0FD;} + .d2-2887586175 .fill-AA5{fill:#F7F8FE;} + .d2-2887586175 .fill-AB4{fill:#EDF0FD;} + .d2-2887586175 .fill-AB5{fill:#F7F8FE;} + .d2-2887586175 .stroke-N1{stroke:#0A0F25;} + .d2-2887586175 .stroke-N2{stroke:#676C7E;} + .d2-2887586175 .stroke-N3{stroke:#9499AB;} + .d2-2887586175 .stroke-N4{stroke:#CFD2DD;} + .d2-2887586175 .stroke-N5{stroke:#DEE1EB;} + .d2-2887586175 .stroke-N6{stroke:#EEF1F8;} + .d2-2887586175 .stroke-N7{stroke:#FFFFFF;} + .d2-2887586175 .stroke-B1{stroke:#0D32B2;} + .d2-2887586175 .stroke-B2{stroke:#0D32B2;} + .d2-2887586175 .stroke-B3{stroke:#E3E9FD;} + .d2-2887586175 .stroke-B4{stroke:#E3E9FD;} + .d2-2887586175 .stroke-B5{stroke:#EDF0FD;} + .d2-2887586175 .stroke-B6{stroke:#F7F8FE;} + .d2-2887586175 .stroke-AA2{stroke:#4A6FF3;} + .d2-2887586175 .stroke-AA4{stroke:#EDF0FD;} + .d2-2887586175 .stroke-AA5{stroke:#F7F8FE;} + .d2-2887586175 .stroke-AB4{stroke:#EDF0FD;} + .d2-2887586175 .stroke-AB5{stroke:#F7F8FE;} + .d2-2887586175 .background-color-N1{background-color:#0A0F25;} + .d2-2887586175 .background-color-N2{background-color:#676C7E;} + .d2-2887586175 .background-color-N3{background-color:#9499AB;} + .d2-2887586175 .background-color-N4{background-color:#CFD2DD;} + .d2-2887586175 .background-color-N5{background-color:#DEE1EB;} + .d2-2887586175 .background-color-N6{background-color:#EEF1F8;} + .d2-2887586175 .background-color-N7{background-color:#FFFFFF;} + .d2-2887586175 .background-color-B1{background-color:#0D32B2;} + .d2-2887586175 .background-color-B2{background-color:#0D32B2;} + .d2-2887586175 .background-color-B3{background-color:#E3E9FD;} + .d2-2887586175 .background-color-B4{background-color:#E3E9FD;} + .d2-2887586175 .background-color-B5{background-color:#EDF0FD;} + .d2-2887586175 .background-color-B6{background-color:#F7F8FE;} + .d2-2887586175 .background-color-AA2{background-color:#4A6FF3;} + .d2-2887586175 .background-color-AA4{background-color:#EDF0FD;} + .d2-2887586175 .background-color-AA5{background-color:#F7F8FE;} + .d2-2887586175 .background-color-AB4{background-color:#EDF0FD;} + .d2-2887586175 .background-color-AB5{background-color:#F7F8FE;} + .d2-2887586175 .color-N1{color:#0A0F25;} + .d2-2887586175 .color-N2{color:#676C7E;} + .d2-2887586175 .color-N3{color:#9499AB;} + .d2-2887586175 .color-N4{color:#CFD2DD;} + .d2-2887586175 .color-N5{color:#DEE1EB;} + .d2-2887586175 .color-N6{color:#EEF1F8;} + .d2-2887586175 .color-N7{color:#FFFFFF;} + .d2-2887586175 .color-B1{color:#0D32B2;} + .d2-2887586175 .color-B2{color:#0D32B2;} + .d2-2887586175 .color-B3{color:#E3E9FD;} + .d2-2887586175 .color-B4{color:#E3E9FD;} + .d2-2887586175 .color-B5{color:#EDF0FD;} + .d2-2887586175 .color-B6{color:#F7F8FE;} + .d2-2887586175 .color-AA2{color:#4A6FF3;} + .d2-2887586175 .color-AA4{color:#EDF0FD;} + .d2-2887586175 .color-AA5{color:#F7F8FE;} + .d2-2887586175 .color-AB4{color:#EDF0FD;} + .d2-2887586175 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>โฌคCheck PINSearch NetworkReadyOffโฌคEnter PINโฌค /check PIN[pin invalid][pin OK][pin OK]network foundpower offpower offpower off + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/glob_dimensions/elk/board.exp.json b/e2etests/testdata/regression/glob_dimensions/elk/board.exp.json index aec42cecc..d6f22abdc 100644 --- a/e2etests/testdata/regression/glob_dimensions/elk/board.exp.json +++ b/e2etests/testdata/regression/glob_dimensions/elk/board.exp.json @@ -7,11 +7,11 @@ "id": "start", "type": "oval", "pos": { - "x": 153, + "x": 163, "y": 12 }, - "width": 30, - "height": 30, + "width": 10, + "height": 10, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -49,10 +49,10 @@ "type": "rectangle", "pos": { "x": 37, - "y": 112 + "y": 103 }, "width": 262, - "height": 658, + "height": 655, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -89,11 +89,11 @@ "id": "Check PIN.start", "type": "oval", "pos": { - "x": 151, - "y": 162 + "x": 161, + "y": 153 }, - "width": 30, - "height": 30, + "width": 10, + "height": 10, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -131,7 +131,7 @@ "type": "rectangle", "pos": { "x": 111, - "y": 262 + "y": 244 }, "width": 111, "height": 66, @@ -172,7 +172,7 @@ "type": "diamond", "pos": { "x": 156, - "y": 509 + "y": 491 }, "width": 20, "height": 20, @@ -211,11 +211,11 @@ "id": "Check PIN.end", "type": "oval", "pos": { - "x": 151, - "y": 690 + "x": 161, + "y": 672 }, - "width": 30, - "height": 30, + "width": 10, + "height": 10, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -244,7 +244,7 @@ "underline": false, "labelWidth": 9, "labelHeight": 21, - "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPosition": "OUTSIDE_BOTTOM_CENTER", "zIndex": 0, "level": 2 }, @@ -253,7 +253,7 @@ "type": "rectangle", "pos": { "x": 29, - "y": 941 + "y": 929 }, "width": 159, "height": 66, @@ -294,7 +294,7 @@ "type": "rectangle", "pos": { "x": 15, - "y": 1178 + "y": 1166 }, "width": 89, "height": 66, @@ -335,7 +335,7 @@ "type": "rectangle", "pos": { "x": 95, - "y": 1415 + "y": 1403 }, "width": 120, "height": 66, @@ -399,11 +399,11 @@ "route": [ { "x": 169, - "y": 42 + "y": 22 }, { "x": 168, - "y": 112 + "y": 103 } ], "animated": false, @@ -437,11 +437,11 @@ "route": [ { "x": 167, - "y": 192 + "y": 163 }, { "x": 166, - "y": 262 + "y": 244 } ], "animated": false, @@ -475,19 +475,19 @@ "route": [ { "x": 123.5, - "y": 328 + "y": 310 }, { "x": 123.5, - "y": 469 + "y": 451 }, { "x": 163.16600036621094, - "y": 469 + "y": 451 }, { "x": 163, - "y": 512 + "y": 494 } ], "animated": false, @@ -521,19 +521,19 @@ "route": [ { "x": 170, - "y": 513 + "y": 495 }, { "x": 169.83299255371094, - "y": 469 + "y": 451 }, { "x": 209.5, - "y": 469 + "y": 451 }, { "x": 209.5, - "y": 328 + "y": 310 } ], "animated": false, @@ -567,11 +567,11 @@ "route": [ { "x": 166, - "y": 528 + "y": 510 }, { "x": 167, - "y": 690 + "y": 672 } ], "animated": false, @@ -605,11 +605,11 @@ "route": [ { "x": 108.75, - "y": 770 + "y": 758 }, { "x": 108.75, - "y": 941 + "y": 929 } ], "animated": false, @@ -643,11 +643,11 @@ "route": [ { "x": 60, - "y": 1007 + "y": 995 }, { "x": 60, - "y": 1178 + "y": 1166 } ], "animated": false, @@ -681,19 +681,19 @@ "route": [ { "x": 240.99899291992188, - "y": 770 + "y": 758 }, { "x": 240.99899291992188, - "y": 1375 + "y": 1363 }, { "x": 185.25, - "y": 1375 + "y": 1363 }, { "x": 185.25, - "y": 1415 + "y": 1403 } ], "animated": false, @@ -727,11 +727,11 @@ "route": [ { "x": 157.5, - "y": 1007 + "y": 995 }, { "x": 157.5, - "y": 1415 + "y": 1403 } ], "animated": false, @@ -765,19 +765,19 @@ "route": [ { "x": 60, - "y": 1244 + "y": 1232 }, { "x": 60, - "y": 1375 + "y": 1363 }, { "x": 125.25, - "y": 1375 + "y": 1363 }, { "x": 125.25, - "y": 1415 + "y": 1403 } ], "animated": false, diff --git a/e2etests/testdata/regression/glob_dimensions/elk/sketch.exp.svg b/e2etests/testdata/regression/glob_dimensions/elk/sketch.exp.svg index d834ef015..0079d186d 100644 --- a/e2etests/testdata/regression/glob_dimensions/elk/sketch.exp.svg +++ b/e2etests/testdata/regression/glob_dimensions/elk/sketch.exp.svg @@ -1,23 +1,23 @@ -โฌคCheck PINSearch NetworkReadyOffโฌคEnter PINโฌค /check PIN[pin invalid][pin OK][pin OK]network foundpower offpower offpower off - - - - - - - - - - - - - - - - - + .d2-1524816052 .fill-N1{fill:#0A0F25;} + .d2-1524816052 .fill-N2{fill:#676C7E;} + .d2-1524816052 .fill-N3{fill:#9499AB;} + .d2-1524816052 .fill-N4{fill:#CFD2DD;} + .d2-1524816052 .fill-N5{fill:#DEE1EB;} + .d2-1524816052 .fill-N6{fill:#EEF1F8;} + .d2-1524816052 .fill-N7{fill:#FFFFFF;} + .d2-1524816052 .fill-B1{fill:#0D32B2;} + .d2-1524816052 .fill-B2{fill:#0D32B2;} + .d2-1524816052 .fill-B3{fill:#E3E9FD;} + .d2-1524816052 .fill-B4{fill:#E3E9FD;} + .d2-1524816052 .fill-B5{fill:#EDF0FD;} + .d2-1524816052 .fill-B6{fill:#F7F8FE;} + .d2-1524816052 .fill-AA2{fill:#4A6FF3;} + .d2-1524816052 .fill-AA4{fill:#EDF0FD;} + .d2-1524816052 .fill-AA5{fill:#F7F8FE;} + .d2-1524816052 .fill-AB4{fill:#EDF0FD;} + .d2-1524816052 .fill-AB5{fill:#F7F8FE;} + .d2-1524816052 .stroke-N1{stroke:#0A0F25;} + .d2-1524816052 .stroke-N2{stroke:#676C7E;} + .d2-1524816052 .stroke-N3{stroke:#9499AB;} + .d2-1524816052 .stroke-N4{stroke:#CFD2DD;} + .d2-1524816052 .stroke-N5{stroke:#DEE1EB;} + .d2-1524816052 .stroke-N6{stroke:#EEF1F8;} + .d2-1524816052 .stroke-N7{stroke:#FFFFFF;} + .d2-1524816052 .stroke-B1{stroke:#0D32B2;} + .d2-1524816052 .stroke-B2{stroke:#0D32B2;} + .d2-1524816052 .stroke-B3{stroke:#E3E9FD;} + .d2-1524816052 .stroke-B4{stroke:#E3E9FD;} + .d2-1524816052 .stroke-B5{stroke:#EDF0FD;} + .d2-1524816052 .stroke-B6{stroke:#F7F8FE;} + .d2-1524816052 .stroke-AA2{stroke:#4A6FF3;} + .d2-1524816052 .stroke-AA4{stroke:#EDF0FD;} + .d2-1524816052 .stroke-AA5{stroke:#F7F8FE;} + .d2-1524816052 .stroke-AB4{stroke:#EDF0FD;} + .d2-1524816052 .stroke-AB5{stroke:#F7F8FE;} + .d2-1524816052 .background-color-N1{background-color:#0A0F25;} + .d2-1524816052 .background-color-N2{background-color:#676C7E;} + .d2-1524816052 .background-color-N3{background-color:#9499AB;} + .d2-1524816052 .background-color-N4{background-color:#CFD2DD;} + .d2-1524816052 .background-color-N5{background-color:#DEE1EB;} + .d2-1524816052 .background-color-N6{background-color:#EEF1F8;} + .d2-1524816052 .background-color-N7{background-color:#FFFFFF;} + .d2-1524816052 .background-color-B1{background-color:#0D32B2;} + .d2-1524816052 .background-color-B2{background-color:#0D32B2;} + .d2-1524816052 .background-color-B3{background-color:#E3E9FD;} + .d2-1524816052 .background-color-B4{background-color:#E3E9FD;} + .d2-1524816052 .background-color-B5{background-color:#EDF0FD;} + .d2-1524816052 .background-color-B6{background-color:#F7F8FE;} + .d2-1524816052 .background-color-AA2{background-color:#4A6FF3;} + .d2-1524816052 .background-color-AA4{background-color:#EDF0FD;} + .d2-1524816052 .background-color-AA5{background-color:#F7F8FE;} + .d2-1524816052 .background-color-AB4{background-color:#EDF0FD;} + .d2-1524816052 .background-color-AB5{background-color:#F7F8FE;} + .d2-1524816052 .color-N1{color:#0A0F25;} + .d2-1524816052 .color-N2{color:#676C7E;} + .d2-1524816052 .color-N3{color:#9499AB;} + .d2-1524816052 .color-N4{color:#CFD2DD;} + .d2-1524816052 .color-N5{color:#DEE1EB;} + .d2-1524816052 .color-N6{color:#EEF1F8;} + .d2-1524816052 .color-N7{color:#FFFFFF;} + .d2-1524816052 .color-B1{color:#0D32B2;} + .d2-1524816052 .color-B2{color:#0D32B2;} + .d2-1524816052 .color-B3{color:#E3E9FD;} + .d2-1524816052 .color-B4{color:#E3E9FD;} + .d2-1524816052 .color-B5{color:#EDF0FD;} + .d2-1524816052 .color-B6{color:#F7F8FE;} + .d2-1524816052 .color-AA2{color:#4A6FF3;} + .d2-1524816052 .color-AA4{color:#EDF0FD;} + .d2-1524816052 .color-AA5{color:#F7F8FE;} + .d2-1524816052 .color-AB4{color:#EDF0FD;} + .d2-1524816052 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>โฌคCheck PINSearch NetworkReadyOffโฌคEnter PINโฌค /check PIN[pin invalid][pin OK][pin OK]network foundpower offpower offpower off + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/grid_image_label_position/dagre/sketch.exp.svg b/e2etests/testdata/regression/grid_image_label_position/dagre/sketch.exp.svg index de3bf9c23..680e3b47e 100644 --- a/e2etests/testdata/regression/grid_image_label_position/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/grid_image_label_position/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -teamwork: having someone to blame - - + .d2-3251595454 .fill-N1{fill:#0A0F25;} + .d2-3251595454 .fill-N2{fill:#676C7E;} + .d2-3251595454 .fill-N3{fill:#9499AB;} + .d2-3251595454 .fill-N4{fill:#CFD2DD;} + .d2-3251595454 .fill-N5{fill:#DEE1EB;} + .d2-3251595454 .fill-N6{fill:#EEF1F8;} + .d2-3251595454 .fill-N7{fill:#FFFFFF;} + .d2-3251595454 .fill-B1{fill:#0D32B2;} + .d2-3251595454 .fill-B2{fill:#0D32B2;} + .d2-3251595454 .fill-B3{fill:#E3E9FD;} + .d2-3251595454 .fill-B4{fill:#E3E9FD;} + .d2-3251595454 .fill-B5{fill:#EDF0FD;} + .d2-3251595454 .fill-B6{fill:#F7F8FE;} + .d2-3251595454 .fill-AA2{fill:#4A6FF3;} + .d2-3251595454 .fill-AA4{fill:#EDF0FD;} + .d2-3251595454 .fill-AA5{fill:#F7F8FE;} + .d2-3251595454 .fill-AB4{fill:#EDF0FD;} + .d2-3251595454 .fill-AB5{fill:#F7F8FE;} + .d2-3251595454 .stroke-N1{stroke:#0A0F25;} + .d2-3251595454 .stroke-N2{stroke:#676C7E;} + .d2-3251595454 .stroke-N3{stroke:#9499AB;} + .d2-3251595454 .stroke-N4{stroke:#CFD2DD;} + .d2-3251595454 .stroke-N5{stroke:#DEE1EB;} + .d2-3251595454 .stroke-N6{stroke:#EEF1F8;} + .d2-3251595454 .stroke-N7{stroke:#FFFFFF;} + .d2-3251595454 .stroke-B1{stroke:#0D32B2;} + .d2-3251595454 .stroke-B2{stroke:#0D32B2;} + .d2-3251595454 .stroke-B3{stroke:#E3E9FD;} + .d2-3251595454 .stroke-B4{stroke:#E3E9FD;} + .d2-3251595454 .stroke-B5{stroke:#EDF0FD;} + .d2-3251595454 .stroke-B6{stroke:#F7F8FE;} + .d2-3251595454 .stroke-AA2{stroke:#4A6FF3;} + .d2-3251595454 .stroke-AA4{stroke:#EDF0FD;} + .d2-3251595454 .stroke-AA5{stroke:#F7F8FE;} + .d2-3251595454 .stroke-AB4{stroke:#EDF0FD;} + .d2-3251595454 .stroke-AB5{stroke:#F7F8FE;} + .d2-3251595454 .background-color-N1{background-color:#0A0F25;} + .d2-3251595454 .background-color-N2{background-color:#676C7E;} + .d2-3251595454 .background-color-N3{background-color:#9499AB;} + .d2-3251595454 .background-color-N4{background-color:#CFD2DD;} + .d2-3251595454 .background-color-N5{background-color:#DEE1EB;} + .d2-3251595454 .background-color-N6{background-color:#EEF1F8;} + .d2-3251595454 .background-color-N7{background-color:#FFFFFF;} + .d2-3251595454 .background-color-B1{background-color:#0D32B2;} + .d2-3251595454 .background-color-B2{background-color:#0D32B2;} + .d2-3251595454 .background-color-B3{background-color:#E3E9FD;} + .d2-3251595454 .background-color-B4{background-color:#E3E9FD;} + .d2-3251595454 .background-color-B5{background-color:#EDF0FD;} + .d2-3251595454 .background-color-B6{background-color:#F7F8FE;} + .d2-3251595454 .background-color-AA2{background-color:#4A6FF3;} + .d2-3251595454 .background-color-AA4{background-color:#EDF0FD;} + .d2-3251595454 .background-color-AA5{background-color:#F7F8FE;} + .d2-3251595454 .background-color-AB4{background-color:#EDF0FD;} + .d2-3251595454 .background-color-AB5{background-color:#F7F8FE;} + .d2-3251595454 .color-N1{color:#0A0F25;} + .d2-3251595454 .color-N2{color:#676C7E;} + .d2-3251595454 .color-N3{color:#9499AB;} + .d2-3251595454 .color-N4{color:#CFD2DD;} + .d2-3251595454 .color-N5{color:#DEE1EB;} + .d2-3251595454 .color-N6{color:#EEF1F8;} + .d2-3251595454 .color-N7{color:#FFFFFF;} + .d2-3251595454 .color-B1{color:#0D32B2;} + .d2-3251595454 .color-B2{color:#0D32B2;} + .d2-3251595454 .color-B3{color:#E3E9FD;} + .d2-3251595454 .color-B4{color:#E3E9FD;} + .d2-3251595454 .color-B5{color:#EDF0FD;} + .d2-3251595454 .color-B6{color:#F7F8FE;} + .d2-3251595454 .color-AA2{color:#4A6FF3;} + .d2-3251595454 .color-AA4{color:#EDF0FD;} + .d2-3251595454 .color-AA5{color:#F7F8FE;} + .d2-3251595454 .color-AB4{color:#EDF0FD;} + .d2-3251595454 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>teamwork: having someone to blame + + \ No newline at end of file diff --git a/e2etests/testdata/regression/just-width/elk/board.exp.json b/e2etests/testdata/regression/just-width/elk/board.exp.json index f88d632ff..90db64280 100644 --- a/e2etests/testdata/regression/just-width/elk/board.exp.json +++ b/e2etests/testdata/regression/just-width/elk/board.exp.json @@ -10,7 +10,7 @@ "x": 12, "y": 12 }, - "width": 262, + "width": 100, "height": 61, "opacity": 1, "strokeDash": 0, @@ -40,7 +40,7 @@ "underline": false, "labelWidth": 262, "labelHeight": 21, - "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPosition": "OUTSIDE_BOTTOM_CENTER", "zIndex": 0, "level": 1 } diff --git a/e2etests/testdata/regression/just-width/elk/sketch.exp.svg b/e2etests/testdata/regression/just-width/elk/sketch.exp.svg index 4125f4e3f..83168ccf1 100644 --- a/e2etests/testdata/regression/just-width/elk/sketch.exp.svg +++ b/e2etests/testdata/regression/just-width/elk/sketch.exp.svg @@ -1,9 +1,9 @@ -teamwork: having someone to blame - - + .d2-1014957270 .fill-N1{fill:#0A0F25;} + .d2-1014957270 .fill-N2{fill:#676C7E;} + .d2-1014957270 .fill-N3{fill:#9499AB;} + .d2-1014957270 .fill-N4{fill:#CFD2DD;} + .d2-1014957270 .fill-N5{fill:#DEE1EB;} + .d2-1014957270 .fill-N6{fill:#EEF1F8;} + .d2-1014957270 .fill-N7{fill:#FFFFFF;} + .d2-1014957270 .fill-B1{fill:#0D32B2;} + .d2-1014957270 .fill-B2{fill:#0D32B2;} + .d2-1014957270 .fill-B3{fill:#E3E9FD;} + .d2-1014957270 .fill-B4{fill:#E3E9FD;} + .d2-1014957270 .fill-B5{fill:#EDF0FD;} + .d2-1014957270 .fill-B6{fill:#F7F8FE;} + .d2-1014957270 .fill-AA2{fill:#4A6FF3;} + .d2-1014957270 .fill-AA4{fill:#EDF0FD;} + .d2-1014957270 .fill-AA5{fill:#F7F8FE;} + .d2-1014957270 .fill-AB4{fill:#EDF0FD;} + .d2-1014957270 .fill-AB5{fill:#F7F8FE;} + .d2-1014957270 .stroke-N1{stroke:#0A0F25;} + .d2-1014957270 .stroke-N2{stroke:#676C7E;} + .d2-1014957270 .stroke-N3{stroke:#9499AB;} + .d2-1014957270 .stroke-N4{stroke:#CFD2DD;} + .d2-1014957270 .stroke-N5{stroke:#DEE1EB;} + .d2-1014957270 .stroke-N6{stroke:#EEF1F8;} + .d2-1014957270 .stroke-N7{stroke:#FFFFFF;} + .d2-1014957270 .stroke-B1{stroke:#0D32B2;} + .d2-1014957270 .stroke-B2{stroke:#0D32B2;} + .d2-1014957270 .stroke-B3{stroke:#E3E9FD;} + .d2-1014957270 .stroke-B4{stroke:#E3E9FD;} + .d2-1014957270 .stroke-B5{stroke:#EDF0FD;} + .d2-1014957270 .stroke-B6{stroke:#F7F8FE;} + .d2-1014957270 .stroke-AA2{stroke:#4A6FF3;} + .d2-1014957270 .stroke-AA4{stroke:#EDF0FD;} + .d2-1014957270 .stroke-AA5{stroke:#F7F8FE;} + .d2-1014957270 .stroke-AB4{stroke:#EDF0FD;} + .d2-1014957270 .stroke-AB5{stroke:#F7F8FE;} + .d2-1014957270 .background-color-N1{background-color:#0A0F25;} + .d2-1014957270 .background-color-N2{background-color:#676C7E;} + .d2-1014957270 .background-color-N3{background-color:#9499AB;} + .d2-1014957270 .background-color-N4{background-color:#CFD2DD;} + .d2-1014957270 .background-color-N5{background-color:#DEE1EB;} + .d2-1014957270 .background-color-N6{background-color:#EEF1F8;} + .d2-1014957270 .background-color-N7{background-color:#FFFFFF;} + .d2-1014957270 .background-color-B1{background-color:#0D32B2;} + .d2-1014957270 .background-color-B2{background-color:#0D32B2;} + .d2-1014957270 .background-color-B3{background-color:#E3E9FD;} + .d2-1014957270 .background-color-B4{background-color:#E3E9FD;} + .d2-1014957270 .background-color-B5{background-color:#EDF0FD;} + .d2-1014957270 .background-color-B6{background-color:#F7F8FE;} + .d2-1014957270 .background-color-AA2{background-color:#4A6FF3;} + .d2-1014957270 .background-color-AA4{background-color:#EDF0FD;} + .d2-1014957270 .background-color-AA5{background-color:#F7F8FE;} + .d2-1014957270 .background-color-AB4{background-color:#EDF0FD;} + .d2-1014957270 .background-color-AB5{background-color:#F7F8FE;} + .d2-1014957270 .color-N1{color:#0A0F25;} + .d2-1014957270 .color-N2{color:#676C7E;} + .d2-1014957270 .color-N3{color:#9499AB;} + .d2-1014957270 .color-N4{color:#CFD2DD;} + .d2-1014957270 .color-N5{color:#DEE1EB;} + .d2-1014957270 .color-N6{color:#EEF1F8;} + .d2-1014957270 .color-N7{color:#FFFFFF;} + .d2-1014957270 .color-B1{color:#0D32B2;} + .d2-1014957270 .color-B2{color:#0D32B2;} + .d2-1014957270 .color-B3{color:#E3E9FD;} + .d2-1014957270 .color-B4{color:#E3E9FD;} + .d2-1014957270 .color-B5{color:#EDF0FD;} + .d2-1014957270 .color-B6{color:#F7F8FE;} + .d2-1014957270 .color-AA2{color:#4A6FF3;} + .d2-1014957270 .color-AA4{color:#EDF0FD;} + .d2-1014957270 .color-AA5{color:#F7F8FE;} + .d2-1014957270 .color-AB4{color:#EDF0FD;} + .d2-1014957270 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>teamwork: having someone to blame + + \ No newline at end of file diff --git a/e2etests/testdata/regression/link_with_ampersand/dagre/sketch.exp.svg b/e2etests/testdata/regression/link_with_ampersand/dagre/sketch.exp.svg index 6d03131aa..9acfedb40 100644 --- a/e2etests/testdata/regression/link_with_ampersand/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/link_with_ampersand/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear + .d2-3267239171 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear diff --git a/e2etests/testdata/stable/animated/elk/sketch.exp.svg b/e2etests/testdata/stable/animated/elk/sketch.exp.svg index fa3a93bef..bffee0710 100644 --- a/e2etests/testdata/stable/animated/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/animated/elk/sketch.exp.svg @@ -1,4 +1,4 @@ -your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear + .d2-838869033 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear diff --git a/e2etests/testdata/stable/array-classes/dagre/sketch.exp.svg b/e2etests/testdata/stable/array-classes/dagre/sketch.exp.svg index f6d96c2bf..f4633a3d0 100644 --- a/e2etests/testdata/stable/array-classes/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/array-classes/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -container

they did it in style

-

a header

+container

they did it in style

+

a header

a line of text and an

{
 	indented: "block",
@@ -845,7 +845,7 @@
 }
 

walk into a bar.

-
+
diff --git a/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json b/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json index 152457511..3a3f429c3 100644 --- a/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json +++ b/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json @@ -58,7 +58,7 @@ "strokeWidth": 2, "borderRadius": 0, "fill": "transparent", - "stroke": "darkorange", + "stroke": "N1", "shadow": false, "3d": false, "multiple": false, @@ -75,7 +75,7 @@ "fontSize": 16, "fontFamily": "DEFAULT", "language": "markdown", - "color": "N1", + "color": "darkorange", "italic": false, "bold": false, "underline": false, @@ -98,7 +98,7 @@ "strokeWidth": 2, "borderRadius": 0, "fill": "#CEEDEE", - "stroke": "red", + "stroke": "N1", "shadow": false, "3d": false, "multiple": false, @@ -115,7 +115,7 @@ "fontSize": 16, "fontFamily": "DEFAULT", "language": "markdown", - "color": "N1", + "color": "red", "italic": false, "bold": false, "underline": false, diff --git a/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg b/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg index 24bea82fe..6a01ad4c5 100644 --- a/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg @@ -1,20 +1,20 @@ -container

they did it in style

-

a header

+container

they did it in style

+

a header

a line of text and an

{
 	indented: "block",
@@ -845,7 +845,7 @@
 }
 

walk into a bar.

-
+
diff --git a/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg b/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg index 60c5b1afa..3223ce950 100644 --- a/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -npm i -g@forge/cliSet up anAtlassian siteView the helloworld appforgetunnelforgeloginforgecreateforgedeployforgeinstallHot reloadchanges?Step 1Step 2Step 3Step 4forgedeployโฌค Forge CLIโฌค Requiredโฌค Optional YesNo - + .d2-29674933 .fill-N1{fill:#0A0F25;} + .d2-29674933 .fill-N2{fill:#676C7E;} + .d2-29674933 .fill-N3{fill:#9499AB;} + .d2-29674933 .fill-N4{fill:#CFD2DD;} + .d2-29674933 .fill-N5{fill:#DEE1EB;} + .d2-29674933 .fill-N6{fill:#EEF1F8;} + .d2-29674933 .fill-N7{fill:#FFFFFF;} + .d2-29674933 .fill-B1{fill:#0D32B2;} + .d2-29674933 .fill-B2{fill:#0D32B2;} + .d2-29674933 .fill-B3{fill:#E3E9FD;} + .d2-29674933 .fill-B4{fill:#E3E9FD;} + .d2-29674933 .fill-B5{fill:#EDF0FD;} + .d2-29674933 .fill-B6{fill:#F7F8FE;} + .d2-29674933 .fill-AA2{fill:#4A6FF3;} + .d2-29674933 .fill-AA4{fill:#EDF0FD;} + .d2-29674933 .fill-AA5{fill:#F7F8FE;} + .d2-29674933 .fill-AB4{fill:#EDF0FD;} + .d2-29674933 .fill-AB5{fill:#F7F8FE;} + .d2-29674933 .stroke-N1{stroke:#0A0F25;} + .d2-29674933 .stroke-N2{stroke:#676C7E;} + .d2-29674933 .stroke-N3{stroke:#9499AB;} + .d2-29674933 .stroke-N4{stroke:#CFD2DD;} + .d2-29674933 .stroke-N5{stroke:#DEE1EB;} + .d2-29674933 .stroke-N6{stroke:#EEF1F8;} + .d2-29674933 .stroke-N7{stroke:#FFFFFF;} + .d2-29674933 .stroke-B1{stroke:#0D32B2;} + .d2-29674933 .stroke-B2{stroke:#0D32B2;} + .d2-29674933 .stroke-B3{stroke:#E3E9FD;} + .d2-29674933 .stroke-B4{stroke:#E3E9FD;} + .d2-29674933 .stroke-B5{stroke:#EDF0FD;} + .d2-29674933 .stroke-B6{stroke:#F7F8FE;} + .d2-29674933 .stroke-AA2{stroke:#4A6FF3;} + .d2-29674933 .stroke-AA4{stroke:#EDF0FD;} + .d2-29674933 .stroke-AA5{stroke:#F7F8FE;} + .d2-29674933 .stroke-AB4{stroke:#EDF0FD;} + .d2-29674933 .stroke-AB5{stroke:#F7F8FE;} + .d2-29674933 .background-color-N1{background-color:#0A0F25;} + .d2-29674933 .background-color-N2{background-color:#676C7E;} + .d2-29674933 .background-color-N3{background-color:#9499AB;} + .d2-29674933 .background-color-N4{background-color:#CFD2DD;} + .d2-29674933 .background-color-N5{background-color:#DEE1EB;} + .d2-29674933 .background-color-N6{background-color:#EEF1F8;} + .d2-29674933 .background-color-N7{background-color:#FFFFFF;} + .d2-29674933 .background-color-B1{background-color:#0D32B2;} + .d2-29674933 .background-color-B2{background-color:#0D32B2;} + .d2-29674933 .background-color-B3{background-color:#E3E9FD;} + .d2-29674933 .background-color-B4{background-color:#E3E9FD;} + .d2-29674933 .background-color-B5{background-color:#EDF0FD;} + .d2-29674933 .background-color-B6{background-color:#F7F8FE;} + .d2-29674933 .background-color-AA2{background-color:#4A6FF3;} + .d2-29674933 .background-color-AA4{background-color:#EDF0FD;} + .d2-29674933 .background-color-AA5{background-color:#F7F8FE;} + .d2-29674933 .background-color-AB4{background-color:#EDF0FD;} + .d2-29674933 .background-color-AB5{background-color:#F7F8FE;} + .d2-29674933 .color-N1{color:#0A0F25;} + .d2-29674933 .color-N2{color:#676C7E;} + .d2-29674933 .color-N3{color:#9499AB;} + .d2-29674933 .color-N4{color:#CFD2DD;} + .d2-29674933 .color-N5{color:#DEE1EB;} + .d2-29674933 .color-N6{color:#EEF1F8;} + .d2-29674933 .color-N7{color:#FFFFFF;} + .d2-29674933 .color-B1{color:#0D32B2;} + .d2-29674933 .color-B2{color:#0D32B2;} + .d2-29674933 .color-B3{color:#E3E9FD;} + .d2-29674933 .color-B4{color:#E3E9FD;} + .d2-29674933 .color-B5{color:#EDF0FD;} + .d2-29674933 .color-B6{color:#F7F8FE;} + .d2-29674933 .color-AA2{color:#4A6FF3;} + .d2-29674933 .color-AA4{color:#EDF0FD;} + .d2-29674933 .color-AA5{color:#F7F8FE;} + .d2-29674933 .color-AB4{color:#EDF0FD;} + .d2-29674933 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>npm i -g@forge/cliSet up anAtlassian siteView the helloworld appforgetunnelforgeloginforgecreateforgedeployforgeinstallHot reloadchanges?Step 1Step 2Step 3Step 4forgedeployโฌค Forge CLIโฌค Requiredโฌค Optional YesNo + - + - + - + - - + + \ No newline at end of file diff --git a/e2etests/testdata/stable/simple_grid_edges/elk/board.exp.json b/e2etests/testdata/stable/simple_grid_edges/elk/board.exp.json index 3247aa247..52e639ce5 100644 --- a/e2etests/testdata/stable/simple_grid_edges/elk/board.exp.json +++ b/e2etests/testdata/stable/simple_grid_edges/elk/board.exp.json @@ -192,7 +192,7 @@ "x": 480, "y": 0 }, - "width": 120, + "width": 100, "height": 60, "opacity": 1, "strokeDash": 0, @@ -408,7 +408,7 @@ "x": 480, "y": 65 }, - "width": 120, + "width": 100, "height": 30, "opacity": 1, "strokeDash": 0, @@ -632,7 +632,7 @@ "x": 480, "y": 100 }, - "width": 120, + "width": 100, "height": 60, "opacity": 1, "strokeDash": 0, @@ -852,7 +852,7 @@ "x": 480, "y": 165 }, - "width": 120, + "width": 100, "height": 30, "opacity": 1, "strokeDash": 0, @@ -1188,7 +1188,7 @@ "x": 480, "y": 200 }, - "width": 120, + "width": 100, "height": 60, "opacity": 1, "strokeDash": 0, @@ -1539,11 +1539,11 @@ "labelPercentage": 0, "route": [ { - "x": 540, + "x": 530, "y": 100 }, { - "x": 540, + "x": 530, "y": 60 } ], @@ -1580,11 +1580,11 @@ "labelPercentage": 0, "route": [ { - "x": 540, + "x": 530, "y": 160 }, { - "x": 540, + "x": 530, "y": 200 } ], diff --git a/e2etests/testdata/stable/simple_grid_edges/elk/sketch.exp.svg b/e2etests/testdata/stable/simple_grid_edges/elk/sketch.exp.svg index a6635f2aa..c02c64467 100644 --- a/e2etests/testdata/stable/simple_grid_edges/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/simple_grid_edges/elk/sketch.exp.svg @@ -1,23 +1,23 @@ -npm i -g@forge/cliSet up anAtlassian siteView the helloworld appforgetunnelforgeloginforgecreateforgedeployforgeinstallHot reloadchanges?Step 1Step 2Step 3Step 4forgedeployโฌค Forge CLIโฌค Requiredโฌค Optional YesNo - + .d2-29674933 .fill-N1{fill:#0A0F25;} + .d2-29674933 .fill-N2{fill:#676C7E;} + .d2-29674933 .fill-N3{fill:#9499AB;} + .d2-29674933 .fill-N4{fill:#CFD2DD;} + .d2-29674933 .fill-N5{fill:#DEE1EB;} + .d2-29674933 .fill-N6{fill:#EEF1F8;} + .d2-29674933 .fill-N7{fill:#FFFFFF;} + .d2-29674933 .fill-B1{fill:#0D32B2;} + .d2-29674933 .fill-B2{fill:#0D32B2;} + .d2-29674933 .fill-B3{fill:#E3E9FD;} + .d2-29674933 .fill-B4{fill:#E3E9FD;} + .d2-29674933 .fill-B5{fill:#EDF0FD;} + .d2-29674933 .fill-B6{fill:#F7F8FE;} + .d2-29674933 .fill-AA2{fill:#4A6FF3;} + .d2-29674933 .fill-AA4{fill:#EDF0FD;} + .d2-29674933 .fill-AA5{fill:#F7F8FE;} + .d2-29674933 .fill-AB4{fill:#EDF0FD;} + .d2-29674933 .fill-AB5{fill:#F7F8FE;} + .d2-29674933 .stroke-N1{stroke:#0A0F25;} + .d2-29674933 .stroke-N2{stroke:#676C7E;} + .d2-29674933 .stroke-N3{stroke:#9499AB;} + .d2-29674933 .stroke-N4{stroke:#CFD2DD;} + .d2-29674933 .stroke-N5{stroke:#DEE1EB;} + .d2-29674933 .stroke-N6{stroke:#EEF1F8;} + .d2-29674933 .stroke-N7{stroke:#FFFFFF;} + .d2-29674933 .stroke-B1{stroke:#0D32B2;} + .d2-29674933 .stroke-B2{stroke:#0D32B2;} + .d2-29674933 .stroke-B3{stroke:#E3E9FD;} + .d2-29674933 .stroke-B4{stroke:#E3E9FD;} + .d2-29674933 .stroke-B5{stroke:#EDF0FD;} + .d2-29674933 .stroke-B6{stroke:#F7F8FE;} + .d2-29674933 .stroke-AA2{stroke:#4A6FF3;} + .d2-29674933 .stroke-AA4{stroke:#EDF0FD;} + .d2-29674933 .stroke-AA5{stroke:#F7F8FE;} + .d2-29674933 .stroke-AB4{stroke:#EDF0FD;} + .d2-29674933 .stroke-AB5{stroke:#F7F8FE;} + .d2-29674933 .background-color-N1{background-color:#0A0F25;} + .d2-29674933 .background-color-N2{background-color:#676C7E;} + .d2-29674933 .background-color-N3{background-color:#9499AB;} + .d2-29674933 .background-color-N4{background-color:#CFD2DD;} + .d2-29674933 .background-color-N5{background-color:#DEE1EB;} + .d2-29674933 .background-color-N6{background-color:#EEF1F8;} + .d2-29674933 .background-color-N7{background-color:#FFFFFF;} + .d2-29674933 .background-color-B1{background-color:#0D32B2;} + .d2-29674933 .background-color-B2{background-color:#0D32B2;} + .d2-29674933 .background-color-B3{background-color:#E3E9FD;} + .d2-29674933 .background-color-B4{background-color:#E3E9FD;} + .d2-29674933 .background-color-B5{background-color:#EDF0FD;} + .d2-29674933 .background-color-B6{background-color:#F7F8FE;} + .d2-29674933 .background-color-AA2{background-color:#4A6FF3;} + .d2-29674933 .background-color-AA4{background-color:#EDF0FD;} + .d2-29674933 .background-color-AA5{background-color:#F7F8FE;} + .d2-29674933 .background-color-AB4{background-color:#EDF0FD;} + .d2-29674933 .background-color-AB5{background-color:#F7F8FE;} + .d2-29674933 .color-N1{color:#0A0F25;} + .d2-29674933 .color-N2{color:#676C7E;} + .d2-29674933 .color-N3{color:#9499AB;} + .d2-29674933 .color-N4{color:#CFD2DD;} + .d2-29674933 .color-N5{color:#DEE1EB;} + .d2-29674933 .color-N6{color:#EEF1F8;} + .d2-29674933 .color-N7{color:#FFFFFF;} + .d2-29674933 .color-B1{color:#0D32B2;} + .d2-29674933 .color-B2{color:#0D32B2;} + .d2-29674933 .color-B3{color:#E3E9FD;} + .d2-29674933 .color-B4{color:#E3E9FD;} + .d2-29674933 .color-B5{color:#EDF0FD;} + .d2-29674933 .color-B6{color:#F7F8FE;} + .d2-29674933 .color-AA2{color:#4A6FF3;} + .d2-29674933 .color-AA4{color:#EDF0FD;} + .d2-29674933 .color-AA5{color:#F7F8FE;} + .d2-29674933 .color-AB4{color:#EDF0FD;} + .d2-29674933 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>npm i -g@forge/cliSet up anAtlassian siteView the helloworld appforgetunnelforgeloginforgecreateforgedeployforgeinstallHot reloadchanges?Step 1Step 2Step 3Step 4forgedeployโฌค Forge CLIโฌค Requiredโฌค Optional YesNo + - + - + - + - - + + \ No newline at end of file diff --git a/e2etests/testdata/stable/sql_table_column_styles/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_table_column_styles/dagre/sketch.exp.svg index d86edd450..d4c5c6a7c 100644 --- a/e2etests/testdata/stable/sql_table_column_styles/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_table_column_styles/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -xyPKabFK I like turtles + .d2-3096218097 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>xyPKabFK I like turtles diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg index c27b67ada..698aafa98 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg @@ -1,4 +1,4 @@ -xyPKabFK I like turtles + .d2-3579465052 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>xyPKabFK I like turtles diff --git a/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg index c58cb1e0c..7f9fb4b91 100644 --- a/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -abcdefgx + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/bidirectional-connection-animation/elk/board.exp.json b/e2etests/testdata/txtar/bidirectional-connection-animation/elk/board.exp.json new file mode 100644 index 000000000..85d12fc27 --- /dev/null +++ b/e2etests/testdata/txtar/bidirectional-connection-animation/elk/board.exp.json @@ -0,0 +1,645 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 68, + "y": 12 + }, + "width": 160, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 12, + "y": 208 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "c", + "type": "rectangle", + "pos": { + "x": 85, + "y": 208 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "d", + "type": "rectangle", + "pos": { + "x": 158, + "y": 208 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "e", + "type": "rectangle", + "pos": { + "x": 232, + "y": 208 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "f", + "type": "rectangle", + "pos": { + "x": 306, + "y": 12 + }, + "width": 51, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "f", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 6, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "g", + "type": "rectangle", + "pos": { + "x": 305, + "y": 208 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "g", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x", + "type": "rectangle", + "pos": { + "x": 427, + "y": 12 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a <-> b)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 100.25, + "y": 78 + }, + { + "x": 100.25, + "y": 118 + }, + { + "x": 38.5, + "y": 118 + }, + { + "x": 38.5, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> c)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "c", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 132.25, + "y": 78 + }, + { + "x": 132.25, + "y": 168 + }, + { + "x": 111.5, + "y": 168 + }, + { + "x": 111.5, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> d)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "d", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 164.25, + "y": 78 + }, + { + "x": 164.25, + "y": 168 + }, + { + "x": 185, + "y": 168 + }, + { + "x": 185, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> e)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "e", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 196.25, + "y": 78 + }, + { + "x": 196.25, + "y": 118 + }, + { + "x": 258.5, + "y": 118 + }, + { + "x": 258.5, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(f <-> g)[0]", + "src": "f", + "srcArrow": "triangle", + "dst": "g", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 332, + "y": 78 + }, + { + "x": 332, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(x -- x)[0]", + "src": "x", + "srcArrow": "none", + "dst": "x", + "dstArrow": "none", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 427.5, + "y": 34 + }, + { + "x": 377.5, + "y": 34 + }, + { + "x": 377.5, + "y": 56 + }, + { + "x": 427.5, + "y": 56 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/bidirectional-connection-animation/elk/sketch.exp.svg b/e2etests/testdata/txtar/bidirectional-connection-animation/elk/sketch.exp.svg new file mode 100644 index 000000000..5bdfdd2c5 --- /dev/null +++ b/e2etests/testdata/txtar/bidirectional-connection-animation/elk/sketch.exp.svg @@ -0,0 +1,108 @@ +abcdefgx + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/connection-underline/dagre/board.exp.json b/e2etests/testdata/txtar/connection-underline/dagre/board.exp.json new file mode 100644 index 000000000..93d7d24b3 --- /dev/null +++ b/e2etests/testdata/txtar/connection-underline/dagre/board.exp.json @@ -0,0 +1,178 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 0, + "y": 187 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "hi", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": true, + "labelWidth": 13, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 26.5, + "y": 65.5 + }, + { + "x": 26.5, + "y": 114.30000305175781 + }, + { + "x": 26.5, + "y": 138.6999969482422 + }, + { + "x": 26.5, + "y": 187.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/connection-underline/dagre/sketch.exp.svg b/e2etests/testdata/txtar/connection-underline/dagre/sketch.exp.svg new file mode 100644 index 000000000..96cee21d5 --- /dev/null +++ b/e2etests/testdata/txtar/connection-underline/dagre/sketch.exp.svg @@ -0,0 +1,107 @@ +ab hi + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/connection-underline/elk/board.exp.json b/e2etests/testdata/txtar/connection-underline/elk/board.exp.json new file mode 100644 index 000000000..a1cde3b44 --- /dev/null +++ b/e2etests/testdata/txtar/connection-underline/elk/board.exp.json @@ -0,0 +1,169 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 12, + "y": 239 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "hi", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": true, + "labelWidth": 13, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 38.5, + "y": 78 + }, + { + "x": 38.5, + "y": 239 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/connection-underline/elk/sketch.exp.svg b/e2etests/testdata/txtar/connection-underline/elk/sketch.exp.svg new file mode 100644 index 000000000..2c1399ced --- /dev/null +++ b/e2etests/testdata/txtar/connection-underline/elk/sketch.exp.svg @@ -0,0 +1,107 @@ +ab hi + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/nested-spread-substitutions-regression/dagre/board.exp.json b/e2etests/testdata/txtar/nested-spread-substitutions-regression/dagre/board.exp.json new file mode 100644 index 000000000..648e0b3f2 --- /dev/null +++ b/e2etests/testdata/txtar/nested-spread-substitutions-regression/dagre/board.exp.json @@ -0,0 +1,219 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "ok", + "type": "rectangle", + "pos": { + "x": 10, + "y": 20 + }, + "width": 157, + "height": 323, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Home", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 68, + "labelHeight": 36, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "ok.dog1", + "type": "oval", + "pos": { + "x": 40, + "y": 50 + }, + "width": 97, + "height": 97, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "dog1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "ok.dog3", + "type": "rectangle", + "pos": { + "x": 49, + "y": 247 + }, + "width": 80, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "dog3", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "ok.(dog1 -> dog3)[0]", + "src": "ok.dog1", + "srcArrow": "none", + "dst": "ok.dog3", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 89, + "y": 147 + }, + { + "x": 88.5999984741211, + "y": 187 + }, + { + "x": 88.5, + "y": 207 + }, + { + "x": 88.5, + "y": 247 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/nested-spread-substitutions-regression/dagre/sketch.exp.svg b/e2etests/testdata/txtar/nested-spread-substitutions-regression/dagre/sketch.exp.svg new file mode 100644 index 000000000..21cd18a74 --- /dev/null +++ b/e2etests/testdata/txtar/nested-spread-substitutions-regression/dagre/sketch.exp.svg @@ -0,0 +1,104 @@ +Homedog1dog3 + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/nested-spread-substitutions-regression/elk/board.exp.json b/e2etests/testdata/txtar/nested-spread-substitutions-regression/elk/board.exp.json new file mode 100644 index 000000000..6505afcec --- /dev/null +++ b/e2etests/testdata/txtar/nested-spread-substitutions-regression/elk/board.exp.json @@ -0,0 +1,210 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "ok", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 197, + "height": 333, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Home", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 68, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "ok.dog1", + "type": "oval", + "pos": { + "x": 62, + "y": 62 + }, + "width": 97, + "height": 97, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "dog1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "ok.dog3", + "type": "rectangle", + "pos": { + "x": 70, + "y": 229 + }, + "width": 80, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "dog3", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "ok.(dog1 -> dog3)[0]", + "src": "ok.dog1", + "srcArrow": "none", + "dst": "ok.dog3", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 111, + "y": 159 + }, + { + "x": 110, + "y": 229 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/nested-spread-substitutions-regression/elk/sketch.exp.svg b/e2etests/testdata/txtar/nested-spread-substitutions-regression/elk/sketch.exp.svg new file mode 100644 index 000000000..5a91dc8bb --- /dev/null +++ b/e2etests/testdata/txtar/nested-spread-substitutions-regression/elk/sketch.exp.svg @@ -0,0 +1,104 @@ +Homedog1dog3 + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/none-fill/dagre/board.exp.json b/e2etests/testdata/txtar/none-fill/dagre/board.exp.json new file mode 100644 index 000000000..af4ed577d --- /dev/null +++ b/e2etests/testdata/txtar/none-fill/dagre/board.exp.json @@ -0,0 +1,140 @@ +{ + "name": "", + "config": { + "sketch": null, + "themeID": 302, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null + }, + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "fillPattern": "none", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 113, + "y": 0 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "fillPattern": "paper", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/none-fill/dagre/sketch.exp.svg b/e2etests/testdata/txtar/none-fill/dagre/sketch.exp.svg new file mode 100644 index 000000000..96711aaa3 --- /dev/null +++ b/e2etests/testdata/txtar/none-fill/dagre/sketch.exp.svg @@ -0,0 +1,1160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ab + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/none-fill/elk/board.exp.json b/e2etests/testdata/txtar/none-fill/elk/board.exp.json new file mode 100644 index 000000000..444981e85 --- /dev/null +++ b/e2etests/testdata/txtar/none-fill/elk/board.exp.json @@ -0,0 +1,140 @@ +{ + "name": "", + "config": { + "sketch": null, + "themeID": 302, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null + }, + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "fillPattern": "none", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 85, + "y": 12 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "fillPattern": "paper", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/none-fill/elk/sketch.exp.svg b/e2etests/testdata/txtar/none-fill/elk/sketch.exp.svg new file mode 100644 index 000000000..fb9934b9d --- /dev/null +++ b/e2etests/testdata/txtar/none-fill/elk/sketch.exp.svg @@ -0,0 +1,1160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ab + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/opacity-zero-route/dagre/board.exp.json b/e2etests/testdata/txtar/opacity-zero-route/dagre/board.exp.json new file mode 100644 index 000000000..c4f256797 --- /dev/null +++ b/e2etests/testdata/txtar/opacity-zero-route/dagre/board.exp.json @@ -0,0 +1,497 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "grid", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 361, + "height": 398, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "grid", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 44, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "grid.a", + "type": "rectangle", + "pos": { + "x": 60, + "y": 60 + }, + "width": 53, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.b", + "type": "rectangle", + "pos": { + "x": 60, + "y": 166 + }, + "width": 53, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.c", + "type": "rectangle", + "pos": { + "x": 60, + "y": 272 + }, + "width": 53, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.d", + "type": "rectangle", + "pos": { + "x": 153, + "y": 60 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.e", + "type": "rectangle", + "pos": { + "x": 153, + "y": 166 + }, + "width": 54, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.f", + "type": "rectangle", + "pos": { + "x": 153, + "y": 272 + }, + "width": 54, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "f", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 6, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.g", + "type": "rectangle", + "pos": { + "x": 247, + "y": 60 + }, + "width": 54, + "height": 119, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "g", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.h", + "type": "rectangle", + "pos": { + "x": 247, + "y": 219 + }, + "width": 54, + "height": 119, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "h", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "out", + "type": "rectangle", + "pos": { + "x": 421, + "y": 166 + }, + "width": 69, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "out", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 24, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(out -> grid.d)[0]", + "src": "out", + "srcArrow": "none", + "dst": "grid.d", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 421, + "y": 186 + }, + { + "x": 207, + "y": 103 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/opacity-zero-route/dagre/sketch.exp.svg b/e2etests/testdata/txtar/opacity-zero-route/dagre/sketch.exp.svg new file mode 100644 index 000000000..a30ccdea9 --- /dev/null +++ b/e2etests/testdata/txtar/opacity-zero-route/dagre/sketch.exp.svg @@ -0,0 +1,104 @@ +gridoutd + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/opacity-zero-route/elk/board.exp.json b/e2etests/testdata/txtar/opacity-zero-route/elk/board.exp.json new file mode 100644 index 000000000..583020b29 --- /dev/null +++ b/e2etests/testdata/txtar/opacity-zero-route/elk/board.exp.json @@ -0,0 +1,497 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "grid", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 361, + "height": 398, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "grid", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 44, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "grid.a", + "type": "rectangle", + "pos": { + "x": 72, + "y": 72 + }, + "width": 53, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.b", + "type": "rectangle", + "pos": { + "x": 72, + "y": 178 + }, + "width": 53, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.c", + "type": "rectangle", + "pos": { + "x": 72, + "y": 284 + }, + "width": 53, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.d", + "type": "rectangle", + "pos": { + "x": 165, + "y": 72 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.e", + "type": "rectangle", + "pos": { + "x": 165, + "y": 178 + }, + "width": 54, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.f", + "type": "rectangle", + "pos": { + "x": 165, + "y": 284 + }, + "width": 54, + "height": 66, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "f", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 6, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.g", + "type": "rectangle", + "pos": { + "x": 259, + "y": 72 + }, + "width": 54, + "height": 119, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "g", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "grid.h", + "type": "rectangle", + "pos": { + "x": 259, + "y": 231 + }, + "width": 54, + "height": 119, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "h", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "out", + "type": "rectangle", + "pos": { + "x": 393, + "y": 178 + }, + "width": 69, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "out", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 24, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(out -> grid.d)[0]", + "src": "out", + "srcArrow": "none", + "dst": "grid.d", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 393, + "y": 195 + }, + { + "x": 219, + "y": 117 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/opacity-zero-route/elk/sketch.exp.svg b/e2etests/testdata/txtar/opacity-zero-route/elk/sketch.exp.svg new file mode 100644 index 000000000..b7c4dcdf6 --- /dev/null +++ b/e2etests/testdata/txtar/opacity-zero-route/elk/sketch.exp.svg @@ -0,0 +1,104 @@ +gridoutd + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/dagre/board.exp.json b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/dagre/board.exp.json new file mode 100644 index 000000000..d4be34b71 --- /dev/null +++ b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/dagre/board.exp.json @@ -0,0 +1,703 @@ +{ + "name": "", + "config": { + "sketch": true, + "themeID": null, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null + }, + "isFolderOnly": false, + "fontFamily": "HandDrawn", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 172, + "y": 0 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 0, + "y": 166 + }, + "width": 55, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 10, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "c", + "type": "rectangle", + "pos": { + "x": 115, + "y": 166 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "d", + "type": "rectangle", + "pos": { + "x": 229, + "y": 166 + }, + "width": 55, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 10, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "e", + "type": "rectangle", + "pos": { + "x": 344, + "y": 166 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "f", + "type": "rectangle", + "pos": { + "x": 457, + "y": 0 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "f", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "g", + "type": "rectangle", + "pos": { + "x": 457, + "y": 166 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "g", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x", + "type": "rectangle", + "pos": { + "x": 571, + "y": 0 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a <-> b)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 172.5, + "y": 46 + }, + { + "x": 56.5, + "y": 102 + }, + { + "x": 27.5, + "y": 126 + }, + { + "x": 27.5, + "y": 166 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> c)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "c", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 176, + "y": 66 + }, + { + "x": 148.8000030517578, + "y": 106 + }, + { + "x": 142, + "y": 126 + }, + { + "x": 142, + "y": 166 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> d)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "d", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 222.5, + "y": 66 + }, + { + "x": 249.6999969482422, + "y": 106 + }, + { + "x": 256.5, + "y": 126 + }, + { + "x": 256.5, + "y": 166 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> e)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "e", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 226.25, + "y": 46.08599853515625 + }, + { + "x": 341.6499938964844, + "y": 102.01699829101562 + }, + { + "x": 370.5, + "y": 126 + }, + { + "x": 370.5, + "y": 166 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(f <-> g)[0]", + "src": "f", + "srcArrow": "triangle", + "dst": "g", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 484, + "y": 66 + }, + { + "x": 484, + "y": 106 + }, + { + "x": 484, + "y": 126 + }, + { + "x": 484, + "y": 166 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(x -- x)[0]", + "src": "x", + "srcArrow": "none", + "dst": "x", + "dstArrow": "none", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 624.666015625, + "y": 16 + }, + { + "x": 646.2659912109375, + "y": 3.1989998817443848 + }, + { + "x": 653, + "y": 0 + }, + { + "x": 655, + "y": 0 + }, + { + "x": 657, + "y": 0 + }, + { + "x": 659.666015625, + "y": 6.599999904632568 + }, + { + "x": 661.666015625, + "y": 16.5 + }, + { + "x": 663.666015625, + "y": 26.399999618530273 + }, + { + "x": 663.666015625, + "y": 39.599998474121094 + }, + { + "x": 661.666015625, + "y": 49.5 + }, + { + "x": 659.666015625, + "y": 59.400001525878906 + }, + { + "x": 646.2659912109375, + "y": 62.79999923706055 + }, + { + "x": 624.666015625, + "y": 50 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/dagre/sketch.exp.svg b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/dagre/sketch.exp.svg new file mode 100644 index 000000000..01ae7f387 --- /dev/null +++ b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/dagre/sketch.exp.svg @@ -0,0 +1,116 @@ + + + + + + + + +abcdefgx + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/elk/board.exp.json b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/elk/board.exp.json new file mode 100644 index 000000000..5abaaf205 --- /dev/null +++ b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/elk/board.exp.json @@ -0,0 +1,653 @@ +{ + "name": "", + "config": { + "sketch": true, + "themeID": null, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null + }, + "isFolderOnly": false, + "fontFamily": "HandDrawn", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 71, + "y": 12 + }, + "width": 160, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 12, + "y": 208 + }, + "width": 55, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 10, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "c", + "type": "rectangle", + "pos": { + "x": 87, + "y": 208 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "d", + "type": "rectangle", + "pos": { + "x": 161, + "y": 208 + }, + "width": 55, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 10, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "e", + "type": "rectangle", + "pos": { + "x": 236, + "y": 208 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "f", + "type": "rectangle", + "pos": { + "x": 309, + "y": 12 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "f", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "g", + "type": "rectangle", + "pos": { + "x": 309, + "y": 208 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "g", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x", + "type": "rectangle", + "pos": { + "x": 433, + "y": 12 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a <-> b)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 103.25, + "y": 78 + }, + { + "x": 103.25, + "y": 118 + }, + { + "x": 39.5, + "y": 118 + }, + { + "x": 39.5, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> c)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "c", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 135.25, + "y": 78 + }, + { + "x": 135.25, + "y": 168 + }, + { + "x": 114, + "y": 168 + }, + { + "x": 114, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> d)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "d", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 167.25, + "y": 78 + }, + { + "x": 167.25, + "y": 168 + }, + { + "x": 188.5, + "y": 168 + }, + { + "x": 188.5, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(a <-> e)[0]", + "src": "a", + "srcArrow": "triangle", + "dst": "e", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 199.25, + "y": 78 + }, + { + "x": 199.25, + "y": 118 + }, + { + "x": 262.5, + "y": 118 + }, + { + "x": 262.5, + "y": 208 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(f <-> g)[0]", + "src": "f", + "srcArrow": "triangle", + "dst": "g", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 336, + "y": 78 + }, + { + "x": 336, + "y": 208 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(x -- x)[0]", + "src": "x", + "srcArrow": "none", + "dst": "x", + "dstArrow": "none", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 433, + "y": 34 + }, + { + "x": 383, + "y": 34 + }, + { + "x": 383, + "y": 56 + }, + { + "x": 433, + "y": 56 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/elk/sketch.exp.svg b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/elk/sketch.exp.svg new file mode 100644 index 000000000..9603d3358 --- /dev/null +++ b/e2etests/testdata/txtar/sketch-bidirectional-connection-animation/elk/sketch.exp.svg @@ -0,0 +1,116 @@ + + + + + + + + +abcdefgx + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/dagre/board.exp.json b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/dagre/board.exp.json new file mode 100644 index 000000000..6e64ad35a --- /dev/null +++ b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/dagre/board.exp.json @@ -0,0 +1,403 @@ +{ + "name": "", + "config": { + "sketch": true, + "themeID": null, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null + }, + "isFolderOnly": false, + "fontFamily": "HandDrawn", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 1, + "y": 0 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 0, + "y": 166 + }, + "width": 55, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 10, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x", + "type": "rectangle", + "pos": { + "x": 115, + "y": 0 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "y", + "type": "rectangle", + "pos": { + "x": 115, + "y": 166 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "y", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "z", + "type": "rectangle", + "pos": { + "x": 116, + "y": 332 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "z", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a <-> b)[0]", + "src": "a", + "srcArrow": "circle", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 27.5, + "y": 66 + }, + { + "x": 27.5, + "y": 106 + }, + { + "x": 27.5, + "y": 126 + }, + { + "x": 27.5, + "y": 166 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(x <-> y)[0]", + "src": "x", + "srcArrow": "circle", + "dst": "y", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 142, + "y": 66 + }, + { + "x": 142, + "y": 106 + }, + { + "x": 142, + "y": 126 + }, + { + "x": 142, + "y": 166 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(y <-> z)[0]", + "src": "y", + "srcArrow": "circle", + "dst": "z", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 142, + "y": 232 + }, + { + "x": 142, + "y": 272 + }, + { + "x": 142, + "y": 292 + }, + { + "x": 142, + "y": 332 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/dagre/sketch.exp.svg new file mode 100644 index 000000000..cc3a74131 --- /dev/null +++ b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/dagre/sketch.exp.svg @@ -0,0 +1,107 @@ + + + + + + + + +abxyz + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/elk/board.exp.json b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/elk/board.exp.json new file mode 100644 index 000000000..aeccd4631 --- /dev/null +++ b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/elk/board.exp.json @@ -0,0 +1,376 @@ +{ + "name": "", + "config": { + "sketch": true, + "themeID": null, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null + }, + "isFolderOnly": false, + "fontFamily": "HandDrawn", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 12, + "y": 148 + }, + "width": 55, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 10, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x", + "type": "rectangle", + "pos": { + "x": 87, + "y": 12 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "y", + "type": "rectangle", + "pos": { + "x": 87, + "y": 148 + }, + "width": 54, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "y", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 9, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "z", + "type": "rectangle", + "pos": { + "x": 87, + "y": 284 + }, + "width": 53, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "z", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 8, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a <-> b)[0]", + "src": "a", + "srcArrow": "circle", + "dst": "b", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 39.5, + "y": 78 + }, + { + "x": 39.5, + "y": 148 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(x <-> y)[0]", + "src": "x", + "srcArrow": "circle", + "dst": "y", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 114, + "y": 78 + }, + { + "x": 114, + "y": 148 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(y <-> z)[0]", + "src": "y", + "srcArrow": "circle", + "dst": "z", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 114, + "y": 214 + }, + { + "x": 114, + "y": 284 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/elk/sketch.exp.svg b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/elk/sketch.exp.svg new file mode 100644 index 000000000..ccf71925b --- /dev/null +++ b/e2etests/testdata/txtar/sketch-mode-circle-arrowhead/elk/sketch.exp.svg @@ -0,0 +1,107 @@ + + + + + + + + +abxyz + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/sql-icon/dagre/sketch.exp.svg b/e2etests/testdata/txtar/sql-icon/dagre/sketch.exp.svg index b10457082..5919e55ac 100644 --- a/e2etests/testdata/txtar/sql-icon/dagre/sketch.exp.svg +++ b/e2etests/testdata/txtar/sql-icon/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ -long label + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/width-smaller-than-label-custom-pos/elk/board.exp.json b/e2etests/testdata/txtar/width-smaller-than-label-custom-pos/elk/board.exp.json new file mode 100644 index 000000000..b9a0cbcde --- /dev/null +++ b/e2etests/testdata/txtar/width-smaller-than-label-custom-pos/elk/board.exp.json @@ -0,0 +1,89 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 20, + "height": 61, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "long label", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 69, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/width-smaller-than-label-custom-pos/elk/sketch.exp.svg b/e2etests/testdata/txtar/width-smaller-than-label-custom-pos/elk/sketch.exp.svg new file mode 100644 index 000000000..6acf351ec --- /dev/null +++ b/e2etests/testdata/txtar/width-smaller-than-label-custom-pos/elk/sketch.exp.svg @@ -0,0 +1,95 @@ +long label + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/width-smaller-than-label/dagre/board.exp.json b/e2etests/testdata/txtar/width-smaller-than-label/dagre/board.exp.json new file mode 100644 index 000000000..e7a9496a4 --- /dev/null +++ b/e2etests/testdata/txtar/width-smaller-than-label/dagre/board.exp.json @@ -0,0 +1,89 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "b", + "type": "person", + "pos": { + "x": 0, + "y": 0 + }, + "width": 64, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B3", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hello there cat", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 101, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/width-smaller-than-label/dagre/sketch.exp.svg b/e2etests/testdata/txtar/width-smaller-than-label/dagre/sketch.exp.svg new file mode 100644 index 000000000..2dfd70484 --- /dev/null +++ b/e2etests/testdata/txtar/width-smaller-than-label/dagre/sketch.exp.svg @@ -0,0 +1,95 @@ +hello there cat + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/width-smaller-than-label/elk/board.exp.json b/e2etests/testdata/txtar/width-smaller-than-label/elk/board.exp.json new file mode 100644 index 000000000..605a1b81b --- /dev/null +++ b/e2etests/testdata/txtar/width-smaller-than-label/elk/board.exp.json @@ -0,0 +1,89 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "b", + "type": "person", + "pos": { + "x": 12, + "y": 12 + }, + "width": 64, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B3", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hello there cat", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 101, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/txtar/width-smaller-than-label/elk/sketch.exp.svg b/e2etests/testdata/txtar/width-smaller-than-label/elk/sketch.exp.svg new file mode 100644 index 000000000..eedaa8d73 --- /dev/null +++ b/e2etests/testdata/txtar/width-smaller-than-label/elk/sketch.exp.svg @@ -0,0 +1,95 @@ +hello there cat + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/chinese/dagre/sketch.exp.svg b/e2etests/testdata/unicode/chinese/dagre/sketch.exp.svg index e3862efc1..27d1bf2a2 100644 --- a/e2etests/testdata/unicode/chinese/dagre/sketch.exp.svg +++ b/e2etests/testdata/unicode/chinese/dagre/sketch.exp.svg @@ -1,4 +1,4 @@ - -`, svgURL, pngURL) +` + sampleSVG := fmt.Sprintf(template, svgURL, pngURL) l := simplelog.FromLibLog(ctx) - out, err := BundleLocal(ctx, l, []byte(sampleSVG), false) + // It doesn't matter what the inputPath is for absolute paths + out, err := BundleLocal(ctx, l, "asdf", []byte(sampleSVG), false) if err != nil { t.Fatal(err) } @@ -208,6 +211,47 @@ width="328" height="587" viewBox="-100 -131 328 587">