Merge branch 'terrastruct:master' into master
80
README.md
|
|
@ -46,34 +46,63 @@ https://user-images.githubusercontent.com/3120367/206125010-bd1fea8e-248a-43e7-8
|
||||||
## What does D2 look like?
|
## What does D2 look like?
|
||||||
|
|
||||||
```d2
|
```d2
|
||||||
# Actors
|
vars: {
|
||||||
hans: Hans Niemann
|
d2-config: {
|
||||||
|
layout-engine: elk
|
||||||
defendants: {
|
# Terminal theme code
|
||||||
mc: Magnus Carlsen
|
theme-id: 300
|
||||||
playmagnus: Play Magnus Group
|
}
|
||||||
chesscom: Chess.com
|
}
|
||||||
naka: Hikaru Nakamura
|
network: {
|
||||||
|
cell tower: {
|
||||||
mc -> playmagnus: Owns majority
|
satellites: {
|
||||||
playmagnus <-> chesscom: Merger talks
|
shape: stored_data
|
||||||
chesscom -> naka: Sponsoring
|
style.multiple: true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Accusations
|
transmitter
|
||||||
hans -> defendants: 'sueing for $100M'
|
|
||||||
|
|
||||||
# Claim
|
satellites -> transmitter: send
|
||||||
defendants.naka -> hans: Accused of cheating on his stream
|
satellites -> transmitter: send
|
||||||
defendants.mc -> hans: Lost then withdrew with accusations
|
satellites -> transmitter: send
|
||||||
defendants.chesscom -> hans: 72 page report of cheating
|
}
|
||||||
|
|
||||||
|
online portal: {
|
||||||
|
ui: {shape: hexagon}
|
||||||
|
}
|
||||||
|
|
||||||
|
data processor: {
|
||||||
|
storage: {
|
||||||
|
shape: cylinder
|
||||||
|
style.multiple: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cell tower.transmitter -> data processor.storage: phone logs
|
||||||
|
}
|
||||||
|
|
||||||
|
user: {
|
||||||
|
shape: person
|
||||||
|
width: 130
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
<p align="center">
|
||||||
|
<img width="400px" src="./docs/assets/example.svg" alt="D2 render example" />
|
||||||
|
</p>
|
||||||
|
|
||||||
<img src="./docs/assets/syntax.png" alt="D2 render example" />
|
> Open in [playground](https://play.d2lang.com/?script=rVLLTsQwDLznKyJxbrWwtyLxFdyR1Zg2ahpHibvLCvXfcdqGfSHthVv8yIxn7APE1OhvpbV5qVryn7ZbQ60dnGjiCn1nPTYa3bCkn_Q7xtF6cJp7HFG3ZHCpLGFlTaP3u51kZjUrj3ykOKyYLTr5REeMhSMBS84yppKRXA9B-BJTRPNhgKEU-OSwHifHNjjp4DitxLNa-SP4NFpmjOoGXVdvl2VBR2_-sWeZgLwTp3SgyOCKnsnKa5PU4xd05OfyIWvTIVKLKdHZExEOHd4Z0p4E3oi2h25s8Ge764uZs4Rr4vqXMfQkAhx1SVanplQWtU0QMCbyEh-t4b7Rz_td6cuo267ryzWPMMiFgHN3XVdu1dkmaPM8K-EiLnGkASsDScj2mQqCFcvj4RGUsSnI_d70Z2GrCptYrVHZTRADXv80VWgL0bVvGfJMoH4A)
|
||||||
|
|
||||||
> Rendered with the TALA layout engine.
|
|
||||||
|
|
||||||
> For more examples, see [./docs/examples](./docs/examples).
|
> 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)
|
- **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)
|
- **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)
|
- **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
|
### 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.
|
this selected list of featured projects using D2.
|
||||||
|
|
||||||
- [ElasticSearch](https://github.com/elastic/beats/blob/main/libbeat/publisher/queue/proxy/diagrams/broker.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
|
- [UC
|
||||||
Berkeley](https://github.com/ucb-bar/hammer/blob/2b5c04d7b7d9ee3c73575efcd7ee0698bd5bfa88/doc/Hammer-Use/hier.d2)
|
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)
|
- [Coronacheck](https://github.com/minvws/nl-covid19-coronacheck-app-ios/blob/e1567e9d1633b3273c537a105bff0e7d3a57ecfe/Diagrams/client-side-datamodel.d2)
|
||||||
|
|
|
||||||
|
|
@ -241,8 +241,9 @@ create_windows_amd64() {
|
||||||
'Name=instance-state-name,Values=pending,running,stopping,stopped' "Name=tag:Name,Values=$REMOTE_NAME" \
|
'Name=instance-state-name,Values=pending,running,stopping,stopped' "Name=tag:Name,Values=$REMOTE_NAME" \
|
||||||
| jq -r '.Reservations[].Instances[].State.Name')
|
| jq -r '.Reservations[].Instances[].State.Name')
|
||||||
if [ -z "$state" ]; then
|
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 \
|
sh_c aws ec2 run-instances \
|
||||||
--image-id=ami-0c5300e833c2b32f3 \
|
--image-id=ami-03ea14ccbeab7b2d5 \
|
||||||
--count=1 \
|
--count=1 \
|
||||||
--instance-type=t3.medium \
|
--instance-type=t3.medium \
|
||||||
--security-groups=windows \
|
--security-groups=windows \
|
||||||
|
|
@ -441,19 +442,22 @@ init_remote_windows() {
|
||||||
header "$REMOTE_NAME"
|
header "$REMOTE_NAME"
|
||||||
wait_remote_host_windows
|
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 <<EOF
|
init_ps1=$(cat <<EOF
|
||||||
\$ProgressPreference = 'SilentlyContinue'
|
\$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
# Bootstrap PowerShell v7
|
# Bootstrap PowerShell v7
|
||||||
if ((\$PSVersionTable.PSVersion).Major -eq 5) {
|
if ((\$PSVersionTable.PSVersion).Major -eq 5) {
|
||||||
Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip
|
Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.8.6 -OutFile .\microsoft.ui.xaml.2.8.6.zip
|
||||||
Expand-Archive -Force .\microsoft.ui.xaml.2.7.3.zip
|
Expand-Archive -Force .\microsoft.ui.xaml.2.8.6.zip
|
||||||
Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx
|
Add-AppxPackage .\microsoft.ui.xaml.2.8.6\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.8.appx
|
||||||
|
|
||||||
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/download/v1.3.2691/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -OutFile .\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
|
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/download/v1.7.10861/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -OutFile .\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
|
||||||
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/download/v1.3.2691/7bcb1a0ab33340daa57fa5b81faec616_License1.xml -OutFile .\7bcb1a0ab33340daa57fa5b81faec616_License1.xml
|
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/download/v1.7.10861/30fe89a9836a4cfbbd3fedce72a58680_License1.xml -OutFile .\30fe89a9836a4cfbbd3fedce72a58680_License1.xml
|
||||||
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx
|
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx
|
||||||
Add-AppxProvisionedPackage -online -PackagePath .\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -LicensePath .\7bcb1a0ab33340daa57fa5b81faec616_License1.xml -DependencyPackagePath Microsoft.VCLibs.x64.14.00.Desktop.appx
|
Add-AppxProvisionedPackage -online -PackagePath .\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -LicensePath .\30fe89a9836a4cfbbd3fedce72a58680_License1.xml -DependencyPackagePath Microsoft.VCLibs.x64.14.00.Desktop.appx
|
||||||
Add-AppxPackage .\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
|
Add-AppxPackage .\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
|
||||||
|
|
||||||
winget install --silent --accept-package-agreements --accept-source-agreements Microsoft.DotNet.SDK.7
|
winget install --silent --accept-package-agreements --accept-source-agreements Microsoft.DotNet.SDK.7
|
||||||
|
|
@ -551,6 +555,7 @@ EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
# Windows and AWS SSM both defeated me.
|
# Windows and AWS SSM both defeated me.
|
||||||
|
# alixander: Step 3's output got mangled for me, so had to replace the line with `printf '%s\n' "$gen_init_ps1" > script` and then open it with vim
|
||||||
FGCOLOR=3 bigheader "WARNING: WINDOWS INITIALIZATION MUST BE COMPLETED MANUALLY OVER RDP AND POWERSHELL!"
|
FGCOLOR=3 bigheader "WARNING: WINDOWS INITIALIZATION MUST BE COMPLETED MANUALLY OVER RDP AND POWERSHELL!"
|
||||||
|
|
||||||
warn '1. Obtain Windows RDP password with:'
|
warn '1. Obtain Windows RDP password with:'
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ cd -- "$(dirname "$0")/../.."
|
||||||
. ./ci/sub/lib.sh
|
. ./ci/sub/lib.sh
|
||||||
|
|
||||||
tag="$(sh_c docker build \
|
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)"
|
-qf ./ci/release/linux/Dockerfile ./ci/release/linux)"
|
||||||
docker_run \
|
docker_run \
|
||||||
-e DRY_RUN \
|
-e DRY_RUN \
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
#### Improvements 🧹
|
#### 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 ⛑️
|
#### 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)
|
||||||
|
|
|
||||||
19
ci/release/changelogs/v0.6.4.md
Normal file
|
|
@ -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)
|
||||||
7
ci/release/changelogs/v0.6.5.md
Normal file
|
|
@ -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)
|
||||||
|
|
@ -862,9 +862,6 @@ func (mk *Key) HasTripleGlob() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mk.EdgeIndex != nil && mk.EdgeIndex.Glob {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if mk.EdgeKey.HasTripleGlob() {
|
if mk.EdgeKey.HasTripleGlob() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -1025,6 +1022,7 @@ type EdgeIndex struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ei1 *EdgeIndex) Equals(ei2 *EdgeIndex) bool {
|
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 {
|
if ei1.Int != ei2.Int {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,10 @@ func (gs *dslGenState) edge() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if src == dst && gs.nodeShapes[dst] == d2target.ShapeSequenceDiagram {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
srcArrow := "-"
|
srcArrow := "-"
|
||||||
if gs.randBool() {
|
if gs.randBool() {
|
||||||
srcArrow = "<"
|
srcArrow = "<"
|
||||||
|
|
@ -265,7 +269,7 @@ func (gs *dslGenState) randStr(n int, inKey bool) string {
|
||||||
func (gs *dslGenState) randShape() string {
|
func (gs *dslGenState) randShape() string {
|
||||||
for {
|
for {
|
||||||
s := shapes[gs.rand.Intn(len(shapes))]
|
s := shapes[gs.rand.Intn(len(shapes))]
|
||||||
if s != d2target.ShapeImage {
|
if s != d2target.ShapeImage && s != d2target.ShapeText {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
|
||||||
if os.Getenv("D2_LSP_MODE") == "1" {
|
if os.Getenv("D2_LSP_MODE") == "1" {
|
||||||
// only the parse result is needed if running d2 for lsp,
|
// only the parse result is needed if running d2 for lsp,
|
||||||
// if this, "fails", the AST is still valid and can be sent
|
// 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)
|
ast, err := d2lib.Parse(ctx, string(input), opts)
|
||||||
|
|
||||||
type LspOutputData struct {
|
type LspOutputData struct {
|
||||||
|
|
@ -529,7 +529,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
|
||||||
ext := getExportExtension(outputPath)
|
ext := getExportExtension(outputPath)
|
||||||
switch ext {
|
switch ext {
|
||||||
case GIF:
|
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 {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
@ -553,7 +553,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
|
||||||
path := []pdf.BoardTitle{
|
path := []pdf.BoardTitle{
|
||||||
{Name: diagram.Root.Label, BoardID: "root"},
|
{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 {
|
if err != nil {
|
||||||
return pdf, false, err
|
return pdf, false, err
|
||||||
}
|
}
|
||||||
|
|
@ -574,7 +574,7 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
|
||||||
path := []pptx.BoardTitle{
|
path := []pptx.BoardTitle{
|
||||||
{Name: "root", BoardID: "root", LinkToSlide: boardIdToIndex["root"] + 1},
|
{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 {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
@ -808,7 +808,7 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug
|
||||||
|
|
||||||
if !diagram.IsFolderOnly {
|
if !diagram.IsFolderOnly {
|
||||||
start := time.Now()
|
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 {
|
if err != nil {
|
||||||
return boards, err
|
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) {
|
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()
|
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 {
|
if err != nil {
|
||||||
return [][]byte{}, err
|
return [][]byte{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -835,7 +835,7 @@ func renderSingle(ctx context.Context, ms *xmain.State, compileDur time.Duration
|
||||||
return [][]byte{out}, nil
|
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
|
toPNG := getExportExtension(outputPath) == PNG
|
||||||
var scale *float64
|
var scale *float64
|
||||||
if opts.Scale != nil {
|
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"
|
cacheImages := ms.Env.Getenv("IMG_CACHE") == "1"
|
||||||
l := simplelog.FromCmdLog(ms.Log)
|
l := simplelog.FromCmdLog(ms.Log)
|
||||||
svg, bundleErr := imgbundler.BundleLocal(ctx, l, svg, cacheImages)
|
svg, bundleErr := imgbundler.BundleLocal(ctx, l, inputPath, svg, cacheImages)
|
||||||
if bundle {
|
if bundle {
|
||||||
var bundleErr2 error
|
var bundleErr2 error
|
||||||
svg, bundleErr2 = imgbundler.BundleRemote(ctx, l, svg, cacheImages)
|
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
|
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
|
var isRoot bool
|
||||||
if doc == nil {
|
if doc == nil {
|
||||||
doc = pdf.Init()
|
doc = pdf.Init()
|
||||||
|
|
@ -940,6 +940,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
|
||||||
Sketch: opts.Sketch,
|
Sketch: opts.Sketch,
|
||||||
Center: opts.Center,
|
Center: opts.Center,
|
||||||
Scale: scale,
|
Scale: scale,
|
||||||
|
ThemeID: opts.ThemeID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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"
|
cacheImages := ms.Env.Getenv("IMG_CACHE") == "1"
|
||||||
l := simplelog.FromCmdLog(ms.Log)
|
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)
|
svg, bundleErr2 := imgbundler.BundleRemote(ctx, l, svg, cacheImages)
|
||||||
bundleErr = multierr.Combine(bundleErr, bundleErr2)
|
bundleErr = multierr.Combine(bundleErr, bundleErr2)
|
||||||
if bundleErr != nil {
|
if bundleErr != nil {
|
||||||
|
|
@ -985,7 +986,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
|
||||||
Name: dl.Root.Label,
|
Name: dl.Root.Label,
|
||||||
BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, LAYERS, dl.Name}, "."),
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -995,7 +996,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
|
||||||
Name: dl.Root.Label,
|
Name: dl.Root.Label,
|
||||||
BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, SCENARIOS, dl.Name}, "."),
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1005,7 +1006,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
|
||||||
Name: dl.Root.Label,
|
Name: dl.Root.Label,
|
||||||
BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, STEPS, dl.Name}, "."),
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1021,7 +1022,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
|
||||||
return svg, nil
|
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
|
var svg []byte
|
||||||
if !diagram.IsFolderOnly {
|
if !diagram.IsFolderOnly {
|
||||||
// gofpdf will print the png img with a slight filter
|
// 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"
|
cacheImages := ms.Env.Getenv("IMG_CACHE") == "1"
|
||||||
l := simplelog.FromCmdLog(ms.Log)
|
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)
|
svg, bundleErr2 := imgbundler.BundleRemote(ctx, l, svg, cacheImages)
|
||||||
bundleErr = multierr.Combine(bundleErr, bundleErr2)
|
bundleErr = multierr.Combine(bundleErr, bundleErr2)
|
||||||
if bundleErr != nil {
|
if bundleErr != nil {
|
||||||
|
|
@ -1119,7 +1120,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present
|
||||||
BoardID: boardID,
|
BoardID: boardID,
|
||||||
LinkToSlide: boardIDToIndex[boardID] + 1,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1131,7 +1132,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present
|
||||||
BoardID: boardID,
|
BoardID: boardID,
|
||||||
LinkToSlide: boardIDToIndex[boardID] + 1,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1143,7 +1144,7 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present
|
||||||
BoardID: boardID,
|
BoardID: boardID,
|
||||||
LinkToSlide: boardIDToIndex[boardID] + 1,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1275,7 +1276,7 @@ func buildBoardIDToIndex(diagram *d2target.Diagram, dictionary map[string]int, p
|
||||||
return dictionary
|
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 {
|
if !diagram.IsFolderOnly {
|
||||||
|
|
||||||
var scale *float64
|
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"
|
cacheImages := ms.Env.Getenv("IMG_CACHE") == "1"
|
||||||
l := simplelog.FromCmdLog(ms.Log)
|
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)
|
svg, bundleErr2 := imgbundler.BundleRemote(ctx, l, svg, cacheImages)
|
||||||
bundleErr = multierr.Combine(bundleErr, bundleErr2)
|
bundleErr = multierr.Combine(bundleErr, bundleErr2)
|
||||||
if bundleErr != nil {
|
if bundleErr != nil {
|
||||||
|
|
@ -1318,21 +1319,21 @@ func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plug
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dl := range diagram.Layers {
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
pngs = append(pngs, layerPNGs...)
|
pngs = append(pngs, layerPNGs...)
|
||||||
}
|
}
|
||||||
for _, dl := range diagram.Scenarios {
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
pngs = append(pngs, scenarioPNGs...)
|
pngs = append(pngs, scenarioPNGs...)
|
||||||
}
|
}
|
||||||
for _, dl := range diagram.Steps {
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) {
|
||||||
|
|
||||||
g := d2graph.NewGraph()
|
g := d2graph.NewGraph()
|
||||||
g.AST = ast
|
g.AST = ast
|
||||||
|
g.BaseAST = ast
|
||||||
c.compileBoard(g, m)
|
c.compileBoard(g, m)
|
||||||
if len(c.err.Errors) > 0 {
|
if len(c.err.Errors) > 0 {
|
||||||
return nil, c.err
|
return nil, c.err
|
||||||
|
|
@ -90,6 +91,7 @@ func (c *compiler) compileBoard(g *d2graph.Graph, ir *d2ir.Map) *d2graph.Graph {
|
||||||
c.validateLabels(g)
|
c.validateLabels(g)
|
||||||
c.validateNear(g)
|
c.validateNear(g)
|
||||||
c.validateEdges(g)
|
c.validateEdges(g)
|
||||||
|
c.validatePositionsCompatibility(g)
|
||||||
|
|
||||||
c.compileBoardsField(g, ir, "layers")
|
c.compileBoardsField(g, ir, "layers")
|
||||||
c.compileBoardsField(g, ir, "scenarios")
|
c.compileBoardsField(g, ir, "scenarios")
|
||||||
|
|
@ -121,7 +123,7 @@ func (c *compiler) compileBoardsField(g *d2graph.Graph, ir *d2ir.Map, fieldName
|
||||||
g2 := d2graph.NewGraph()
|
g2 := d2graph.NewGraph()
|
||||||
g2.Parent = g
|
g2.Parent = g
|
||||||
g2.AST = f.Map().AST().(*d2ast.Map)
|
g2.AST = f.Map().AST().(*d2ast.Map)
|
||||||
g2.BaseAST = findFieldAST(g.AST, f)
|
g2.BaseAST = findFieldAST(g.BaseAST, f)
|
||||||
c.compileBoard(g2, f.Map())
|
c.compileBoard(g2, f.Map())
|
||||||
g2.Name = f.Name
|
g2.Name = f.Name
|
||||||
switch fieldName {
|
switch fieldName {
|
||||||
|
|
@ -337,11 +339,11 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Parent != nil {
|
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")
|
c.errorf(f.LastRef().AST(), "sql_table columns cannot have children")
|
||||||
return
|
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")
|
c.errorf(f.LastRef().AST(), "class fields cannot have children")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -510,7 +512,7 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
attrs.Shape.Value = scalar.ScalarString()
|
attrs.Shape.Value = scalar.ScalarString()
|
||||||
if attrs.Shape.Value == d2target.ShapeCode {
|
if strings.EqualFold(attrs.Shape.Value, d2target.ShapeCode) {
|
||||||
// Explicit code shape is plaintext.
|
// Explicit code shape is plaintext.
|
||||||
attrs.Language = d2target.ShapeText
|
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.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`)
|
c.errorf(obj.Style.DoubleBorder.MapKey, `key "double-border" can only be applied to squares, rectangles, circles, ovals`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "shape":
|
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`)
|
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))
|
c.errorf(f.LastPrimaryKey(), fmt.Sprintf(`invalid shape, can only set "%s" for arrowheads`, obj.Shape.Value))
|
||||||
}
|
}
|
||||||
case "constraint":
|
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`)
|
c.errorf(f.LastPrimaryKey(), `"constraint" keyword can only be used in "sql_table" shapes`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
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.")
|
c.errorf(f.LastRef().AST(), "image shapes cannot have children.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1043,7 +1045,7 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
|
|
||||||
func (c *compiler) validateLabels(g *d2graph.Graph) {
|
func (c *compiler) validateLabels(g *d2graph.Graph) {
|
||||||
for _, obj := range g.Objects {
|
for _, obj := range g.Objects {
|
||||||
if obj.Shape.Value != d2target.ShapeText {
|
if !strings.EqualFold(obj.Shape.Value, d2target.ShapeText) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if obj.Attributes.Language != "" {
|
if obj.Attributes.Language != "" {
|
||||||
|
|
@ -1097,6 +1099,14 @@ func (c *compiler) validateNear(g *d2graph.Graph) {
|
||||||
continue
|
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 {
|
} else if isConst {
|
||||||
if obj.Parent != g.Root {
|
if obj.Parent != g.Root {
|
||||||
c.errorf(obj.NearKey, "constant near keys can only be set on root level shapes")
|
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) {
|
func (c *compiler) validateEdges(g *d2graph.Graph) {
|
||||||
for _, edge := range g.Edges {
|
for _, edge := range g.Edges {
|
||||||
// edges from a grid to something outside is ok
|
// edges from a grid to something outside is ok
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"oss.terrastruct.com/util-go/assert"
|
"oss.terrastruct.com/util-go/assert"
|
||||||
"oss.terrastruct.com/util-go/diff"
|
"oss.terrastruct.com/util-go/diff"
|
||||||
|
"oss.terrastruct.com/util-go/mapfs"
|
||||||
|
|
||||||
"oss.terrastruct.com/d2/d2compiler"
|
"oss.terrastruct.com/d2/d2compiler"
|
||||||
"oss.terrastruct.com/d2/d2format"
|
"oss.terrastruct.com/d2/d2format"
|
||||||
|
|
@ -23,6 +24,8 @@ func TestCompile(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
text string
|
text string
|
||||||
|
// For tests that use imports, define `index.d2` as text and other files here
|
||||||
|
files map[string]string
|
||||||
|
|
||||||
expErr string
|
expErr string
|
||||||
assertions func(t *testing.T, g *d2graph.Graph)
|
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",
|
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`,
|
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",
|
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
|
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`,
|
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 {
|
for _, tc := range testCases {
|
||||||
tc := tc
|
tc := tc
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
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())
|
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 tc.expErr != "" {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error with: %q", tc.expErr)
|
t.Fatalf("expected error with: %q", tc.expErr)
|
||||||
|
|
@ -2991,6 +3086,22 @@ steps: {
|
||||||
assert.True(t, g.IsFolderOnly)
|
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",
|
name: "scenarios_edge_index",
|
||||||
run: func(t *testing.T) {
|
run: func(t *testing.T) {
|
||||||
|
|
@ -3239,6 +3350,17 @@ y: null
|
||||||
assert.Equal(t, 0, len(g.Edges))
|
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",
|
name: "delete-multiple-connections",
|
||||||
run: func(t *testing.T) {
|
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)
|
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",
|
name: "single-quoted",
|
||||||
run: func(t *testing.T) {
|
run: func(t *testing.T) {
|
||||||
|
|
@ -4329,6 +4469,29 @@ container_2: {
|
||||||
assert.Equal(t, 4, len(g.Objects))
|
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 {
|
for _, tc := range tca {
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,9 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection
|
||||||
if edge.Style.Bold != nil {
|
if edge.Style.Bold != nil {
|
||||||
connection.Bold, _ = strconv.ParseBool(edge.Style.Bold.Value)
|
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 {
|
if theme != nil && theme.SpecialRules.Mono {
|
||||||
connection.FontFamily = "mono"
|
connection.FontFamily = "mono"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,7 @@ func (obj *Object) GetFill() string {
|
||||||
return color.N7
|
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 level == 1 {
|
||||||
if !obj.IsContainer() {
|
if !obj.IsContainer() {
|
||||||
return color.B6
|
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.
|
// 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
|
// 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) {
|
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)
|
dslShape := strings.ToLower(obj.Shape.Value)
|
||||||
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape]
|
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape]
|
||||||
s := shape.NewShape(shapeType, geo.NewBox(geo.NewPoint(0, 0), contentWidth, contentHeight))
|
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 {
|
} else {
|
||||||
fitWidth, fitHeight = s.GetDimensionsToFit(contentWidth, contentHeight, paddingX, paddingY)
|
fitWidth, fitHeight = s.GetDimensionsToFit(contentWidth, contentHeight, paddingX, paddingY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.Width = math.Max(float64(desiredWidth), fitWidth)
|
||||||
obj.Height = math.Max(float64(desiredHeight), fitHeight)
|
obj.Height = math.Max(float64(desiredHeight), fitHeight)
|
||||||
|
}
|
||||||
|
|
||||||
if s.AspectRatio1() {
|
if s.AspectRatio1() {
|
||||||
sideLength := math.Max(obj.Width, obj.Height)
|
sideLength := math.Max(obj.Width, obj.Height)
|
||||||
obj.Width = sideLength
|
obj.Width = sideLength
|
||||||
|
|
@ -1816,6 +1827,7 @@ var LabelPositionsMapping = map[string]label.Position{
|
||||||
}
|
}
|
||||||
|
|
||||||
var FillPatterns = []string{
|
var FillPatterns = []string{
|
||||||
|
"none",
|
||||||
"dots",
|
"dots",
|
||||||
"lines",
|
"lines",
|
||||||
"grain",
|
"grain",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var root Object
|
var root Object
|
||||||
convert(sg.Root, &root)
|
Convert(sg.Root, &root)
|
||||||
g.Root = &root
|
g.Root = &root
|
||||||
root.Graph = g
|
root.Graph = g
|
||||||
g.RootLevel = sg.RootLevel
|
g.RootLevel = sg.RootLevel
|
||||||
|
|
@ -38,7 +38,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error {
|
||||||
var objects []*Object
|
var objects []*Object
|
||||||
for _, so := range sg.Objects {
|
for _, so := range sg.Objects {
|
||||||
var o Object
|
var o Object
|
||||||
if err := convert(so, &o); err != nil {
|
if err := Convert(so, &o); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.Graph = g
|
o.Graph = g
|
||||||
|
|
@ -67,7 +67,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error {
|
||||||
var edges []*Edge
|
var edges []*Edge
|
||||||
for _, se := range sg.Edges {
|
for _, se := range sg.Edges {
|
||||||
var e Edge
|
var e Edge
|
||||||
if err := convert(se, &e); err != nil {
|
if err := Convert(se, &e); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ func SerializeGraph(g *Graph) ([]byte, error) {
|
||||||
|
|
||||||
var sedges []SerializedEdge
|
var sedges []SerializedEdge
|
||||||
for _, e := range g.Edges {
|
for _, e := range g.Edges {
|
||||||
se, err := toSerializedEdge(e)
|
se, err := ToSerializedEdge(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +121,7 @@ func SerializeGraph(g *Graph) ([]byte, error) {
|
||||||
|
|
||||||
func toSerializedObject(o *Object) (SerializedObject, error) {
|
func toSerializedObject(o *Object) (SerializedObject, error) {
|
||||||
var so SerializedObject
|
var so SerializedObject
|
||||||
if err := convert(o, &so); err != nil {
|
if err := Convert(o, &so); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,9 +138,9 @@ func toSerializedObject(o *Object) (SerializedObject, error) {
|
||||||
return so, nil
|
return so, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSerializedEdge(e *Edge) (SerializedEdge, error) {
|
func ToSerializedEdge(e *Edge) (SerializedEdge, error) {
|
||||||
var se SerializedEdge
|
var se SerializedEdge
|
||||||
if err := convert(e, &se); err != nil {
|
if err := Convert(e, &se); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ func toSerializedEdge(e *Edge) (SerializedEdge, error) {
|
||||||
return se, nil
|
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)
|
b, err := json.Marshal(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ type compiler struct {
|
||||||
imports []string
|
imports []string
|
||||||
// importStack is used to detect cyclic imports.
|
// importStack is used to detect cyclic imports.
|
||||||
importStack []string
|
importStack []string
|
||||||
// importCache enables reuse of files imported multiple times.
|
seenImports map[string]struct{}
|
||||||
importCache map[string]*Map
|
|
||||||
utf16Pos bool
|
utf16Pos bool
|
||||||
|
|
||||||
// Stack of globs that must be recomputed at each new object in and below the current scope.
|
// 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{},
|
err: &d2parser.ParseError{},
|
||||||
fs: opts.FS,
|
fs: opts.FS,
|
||||||
|
|
||||||
importCache: make(map[string]*Map),
|
seenImports: make(map[string]struct{}),
|
||||||
utf16Pos: opts.UTF16Pos,
|
utf16Pos: opts.UTF16Pos,
|
||||||
}
|
}
|
||||||
m := &Map{}
|
m := &Map{}
|
||||||
|
|
@ -127,14 +126,21 @@ func (c *compiler) compileSubstitutions(m *Map, varsStack []*Map) {
|
||||||
varsStack = append([]*Map{f.Map()}, varsStack...)
|
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 {
|
if f.Primary() != nil {
|
||||||
c.resolveSubstitutions(varsStack, f)
|
removed := c.resolveSubstitutions(varsStack, f)
|
||||||
|
if removed {
|
||||||
|
i--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if arr, ok := f.Composite.(*Array); ok {
|
if arr, ok := f.Composite.(*Array); ok {
|
||||||
for _, val := range arr.Values {
|
for _, val := range arr.Values {
|
||||||
if scalar, ok := val.(*Scalar); ok {
|
if scalar, ok := val.(*Scalar); ok {
|
||||||
c.resolveSubstitutions(varsStack, scalar)
|
removed := c.resolveSubstitutions(varsStack, scalar)
|
||||||
|
if removed {
|
||||||
|
i--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if f.Map() != nil {
|
} 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 subbed bool
|
||||||
var resolvedField *Field
|
var resolvedField *Field
|
||||||
|
|
||||||
|
|
@ -264,6 +270,7 @@ func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) {
|
||||||
for i, f2 := range m.Fields {
|
for i, f2 := range m.Fields {
|
||||||
if n == f2 {
|
if n == f2 {
|
||||||
m.Fields = append(m.Fields[:i], m.Fields[i+1:]...)
|
m.Fields = append(m.Fields[:i], m.Fields[i+1:]...)
|
||||||
|
removedField = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -334,6 +341,7 @@ func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) {
|
||||||
s.Coalesce()
|
s.Coalesce()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return removedField
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) resolveSubstitution(vars *Map, substitution *d2ast.Substitution) *Field {
|
func (c *compiler) resolveSubstitution(vars *Map, substitution *d2ast.Substitution) *Field {
|
||||||
|
|
@ -361,6 +369,9 @@ func (c *compiler) overlay(base *Map, f *Field) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
base = base.CopyBase(f)
|
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())
|
OverlayMap(base, f.Map())
|
||||||
f.Composite = base
|
f.Composite = base
|
||||||
}
|
}
|
||||||
|
|
@ -381,6 +392,9 @@ func (g *globContext) prefixed(dst *Map) *globContext {
|
||||||
if len(prefix.Path) > 0 {
|
if len(prefix.Path) > 0 {
|
||||||
g2.refctx.Key.Key = prefix
|
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
|
return g2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,6 +424,7 @@ func (c *compiler) ampersandFilterMap(dst *Map, ast, scopeAST *d2ast.Map) bool {
|
||||||
ks = d2format.Format(d2ast.MakeKeyPath(BoardIDA(dst)))
|
ks = d2format.Format(d2ast.MakeKeyPath(BoardIDA(dst)))
|
||||||
}
|
}
|
||||||
delete(gctx.appliedFields, ks)
|
delete(gctx.appliedFields, ks)
|
||||||
|
delete(gctx.appliedEdges, ks)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -497,6 +512,7 @@ func (c *compiler) compileMap(dst *Map, ast, scopeAST *d2ast.Map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayMap(dst, impn.Map())
|
OverlayMap(dst, impn.Map())
|
||||||
|
c.updateLinks(dst)
|
||||||
|
|
||||||
if impnf, ok := impn.(*Field); ok {
|
if impnf, ok := impn.(*Field); ok {
|
||||||
if impnf.Primary_ != nil {
|
if impnf.Primary_ != nil {
|
||||||
|
|
@ -979,7 +995,7 @@ func (c *compiler) compileEdges(refctx *RefContext) {
|
||||||
func (c *compiler) _compileEdges(refctx *RefContext) {
|
func (c *compiler) _compileEdges(refctx *RefContext) {
|
||||||
eida := NewEdgeIDs(refctx.Key)
|
eida := NewEdgeIDs(refctx.Key)
|
||||||
for i, eid := range eida {
|
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)
|
refctx.ScopeMap.DeleteEdge(eid)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -997,6 +1013,10 @@ func (c *compiler) _compileEdges(refctx *RefContext) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, e := range ea {
|
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{
|
e.References = append(e.References, &EdgeReference{
|
||||||
Context_: refctx,
|
Context_: refctx,
|
||||||
DueToGlob_: len(c.globRefContextStack) > 0,
|
DueToGlob_: len(c.globRefContextStack) > 0,
|
||||||
|
|
|
||||||
20
d2ir/d2ir.go
|
|
@ -950,14 +950,21 @@ func (m *Map) DeleteField(ida ...string) *Field {
|
||||||
}
|
}
|
||||||
if len(rest) == 0 {
|
if len(rest) == 0 {
|
||||||
for _, fr := range f.References {
|
for _, fr := range f.References {
|
||||||
for _, e := range m.Edges {
|
currM := m
|
||||||
|
for currM != nil {
|
||||||
|
for _, e := range currM.Edges {
|
||||||
for _, er := range e.References {
|
for _, er := range e.References {
|
||||||
if er.Context_ == fr.Context_ {
|
if er.Context_ == fr.Context_ {
|
||||||
m.DeleteEdge(e.ID)
|
currM.DeleteEdge(e.ID)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if NodeBoardKind(currM) != "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
currM = ParentMap(currM)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m.Fields = append(m.Fields[:i], m.Fields[i+1:]...)
|
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{}{}
|
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 {
|
if m == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
astMap := &d2ast.Map{}
|
astMap := &d2ast.Map{
|
||||||
if m.Root() {
|
Range: d2ast.MakeRange(",0:0:0-1:0:0"),
|
||||||
astMap.Range = d2ast.MakeRange(",0:0:0-1:0:0")
|
|
||||||
} else {
|
|
||||||
astMap.Range = d2ast.MakeRange(",1:0:0-2:0:0")
|
|
||||||
}
|
}
|
||||||
for _, f := range m.Fields {
|
for _, f := range m.Fields {
|
||||||
astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(f.AST().(d2ast.MapNode)))
|
astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(f.AST().(d2ast.MapNode)))
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,21 @@ x -> y
|
||||||
assertQuery(t, m, 0, 0, 0.1, "(x -> y)[1].style.opacity")
|
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",
|
name: "lazy-filter",
|
||||||
run: func(t testing.TB) {
|
run: func(t testing.TB) {
|
||||||
|
|
|
||||||
|
|
@ -82,16 +82,11 @@ func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) {
|
||||||
|
|
||||||
// Only get immediate imports.
|
// Only get immediate imports.
|
||||||
if len(c.importStack) == 2 {
|
if len(c.importStack) == 2 {
|
||||||
if _, ok := c.importCache[impPath]; !ok {
|
if _, ok := c.seenImports[impPath]; !ok {
|
||||||
c.imports = append(c.imports, imp.PathWithPre())
|
c.imports = append(c.imports, imp.PathWithPre())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ir, ok := c.importCache[impPath]
|
|
||||||
if ok {
|
|
||||||
return ir, true
|
|
||||||
}
|
|
||||||
|
|
||||||
var f fs.File
|
var f fs.File
|
||||||
var err error
|
var err error
|
||||||
if c.fs == nil {
|
if c.fs == nil {
|
||||||
|
|
@ -113,13 +108,13 @@ func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
ir = &Map{}
|
ir := &Map{}
|
||||||
ir.initRoot()
|
ir.initRoot()
|
||||||
ir.parent.(*Field).References[0].Context_.Scope = ast
|
ir.parent.(*Field).References[0].Context_.Scope = ast
|
||||||
|
|
||||||
c.compileMap(ir, ast, ast)
|
c.compileMap(ir, ast, ast)
|
||||||
|
|
||||||
c.importCache[impPath] = ir
|
c.seenImports[impPath] = struct{}{}
|
||||||
|
|
||||||
return ir, true
|
return ir, true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ label: meow`,
|
||||||
_, err := compileFS(t, "index.d2", map[string]string{
|
_, err := compileFS(t, "index.d2", map[string]string{
|
||||||
"index.d2": "...@'./../x.d2'",
|
"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`)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,79 @@ layers.x: { wrapper.p }
|
||||||
assertQuery(t, m, 0, 0, nil, "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",
|
name: "double-glob/edge/1",
|
||||||
run: func(t testing.TB) {
|
run: func(t testing.TB) {
|
||||||
|
|
|
||||||
|
|
@ -570,6 +570,13 @@ func positionLabelsIcons(obj *d2graph.Object) {
|
||||||
} else {
|
} else {
|
||||||
obj.LabelPosition = go2.Pointer(label.InsideMiddleCenter.String())
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1148,5 +1148,12 @@ func positionLabelsIcons(obj *d2graph.Object) {
|
||||||
} else {
|
} else {
|
||||||
obj.LabelPosition = go2.Pointer(label.InsideMiddleCenter.String())
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
245
d2oracle/edit.go
|
|
@ -199,7 +199,7 @@ func ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey,
|
||||||
|
|
||||||
refs := edge.References
|
refs := edge.References
|
||||||
if baseAST != g.AST {
|
if baseAST != g.AST {
|
||||||
refs = getWriteableEdgeRefs(edge, baseAST)
|
refs = GetWriteableEdgeRefs(edge, baseAST)
|
||||||
if len(refs) == 0 || refs[0].ScopeAST != baseAST {
|
if len(refs) == 0 || refs[0].ScopeAST != baseAST {
|
||||||
// TODO null
|
// TODO null
|
||||||
return nil, OutsideScopeError{}
|
return nil, OutsideScopeError{}
|
||||||
|
|
@ -383,11 +383,11 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
obj = o
|
obj = o
|
||||||
imported = IsImported(baseAST, obj)
|
imported = IsImportedObj(baseAST, obj)
|
||||||
|
|
||||||
var maybeNewScope *d2ast.Map
|
var maybeNewScope *d2ast.Map
|
||||||
if baseAST != g.AST || imported {
|
if baseAST != g.AST || imported {
|
||||||
writeableRefs := getWriteableRefs(obj, baseAST)
|
writeableRefs := GetWriteableRefs(obj, baseAST)
|
||||||
for _, ref := range writeableRefs {
|
for _, ref := range writeableRefs {
|
||||||
if ref.MapKey != nil && ref.MapKey.Value.Map != nil {
|
if ref.MapKey != nil && ref.MapKey.Value.Map != nil {
|
||||||
maybeNewScope = ref.MapKey.Value.Map
|
maybeNewScope = ref.MapKey.Value.Map
|
||||||
|
|
@ -414,7 +414,7 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
writeableLabelMK := true
|
writeableLabelMK := true
|
||||||
var objK *d2ast.Key
|
var objK *d2ast.Key
|
||||||
if baseAST != g.AST || imported {
|
if baseAST != g.AST || imported {
|
||||||
writeableRefs := getWriteableRefs(obj, baseAST)
|
writeableRefs := GetWriteableRefs(obj, baseAST)
|
||||||
if len(writeableRefs) > 0 {
|
if len(writeableRefs) > 0 {
|
||||||
objK = writeableRefs[0].MapKey
|
objK = writeableRefs[0].MapKey
|
||||||
}
|
}
|
||||||
|
|
@ -429,6 +429,19 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
break
|
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
|
var m *d2ast.Map
|
||||||
if objK != nil {
|
if objK != nil {
|
||||||
|
|
@ -481,12 +494,17 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("edge not found")
|
return errors.New("edge not found")
|
||||||
}
|
}
|
||||||
|
imported = IsImportedEdge(baseAST, edge)
|
||||||
refs := edge.References
|
refs := edge.References
|
||||||
if baseAST != g.AST {
|
if baseAST != g.AST || imported {
|
||||||
refs = getWriteableEdgeRefs(edge, baseAST)
|
refs = GetWriteableEdgeRefs(edge, baseAST)
|
||||||
}
|
}
|
||||||
onlyInChain := true
|
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
|
// TODO merge flat edgekeys
|
||||||
// E.g. this can group into a map
|
// E.g. this can group into a map
|
||||||
// (y -> z)[0].style.opacity: 0.4
|
// (y -> z)[0].style.opacity: 0.4
|
||||||
|
|
@ -496,6 +514,8 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
onlyInChain = false
|
onlyInChain = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ref.MapKey.EdgeIndex == nil || !ref.MapKey.EdgeIndex.Glob {
|
||||||
// If a ref has an exact match on this key, just change the value
|
// If a ref has an exact match on this key, just change the value
|
||||||
tmp1 := *ref.MapKey
|
tmp1 := *ref.MapKey
|
||||||
tmp2 := *mk
|
tmp2 := *mk
|
||||||
|
|
@ -508,8 +528,17 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if onlyInChain {
|
if onlyInChain {
|
||||||
|
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)
|
appendMapKey(scope, mk)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
attrs = edge.Attributes
|
attrs = edge.Attributes
|
||||||
|
|
@ -533,7 +562,7 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
foundMap = true
|
foundMap = true
|
||||||
scope = ref.MapKey.Value.Map
|
scope = ref.MapKey.Value.Map
|
||||||
for _, n := range scope.Nodes {
|
for _, n := range scope.Nodes {
|
||||||
if n.MapKey.Value.Map == nil {
|
if n.MapKey == nil || n.MapKey.Value.Map == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.MapKey.Key == nil || len(n.MapKey.Key.Path) != 1 {
|
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 {
|
if s.MapKey.Range.Path != baseAST.Range.Path {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
// Globs are also not writeable
|
||||||
|
if s.MapKey.HasGlob() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s != nil && s.MapKey != nil && !ir.InClass(s.MapKey)
|
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":
|
case "source-arrowhead", "target-arrowhead":
|
||||||
var arrowhead *d2graph.Attributes
|
var arrowhead *d2graph.Attributes
|
||||||
if reservedKey == "source-arrowhead" {
|
if reservedKey == "source-arrowhead" {
|
||||||
|
if edge.SrcArrowhead != nil {
|
||||||
|
attrs = *edge.SrcArrowhead
|
||||||
|
}
|
||||||
arrowhead = edge.SrcArrowhead
|
arrowhead = edge.SrcArrowhead
|
||||||
} else {
|
} else {
|
||||||
|
if edge.DstArrowhead != nil {
|
||||||
|
attrs = *edge.DstArrowhead
|
||||||
|
}
|
||||||
arrowhead = edge.DstArrowhead
|
arrowhead = edge.DstArrowhead
|
||||||
}
|
}
|
||||||
if arrowhead != nil {
|
if arrowhead != nil {
|
||||||
if reservedTargetKey == "" {
|
if reservedTargetKey == "" {
|
||||||
if len(mk.Key.Path[reservedIndex:]) != 2 {
|
if len(mk.Key.Path[reservedIndex:]) < 2 {
|
||||||
return errors.New("malformed style setting, expected 2 part path")
|
return errors.New("malformed style setting, expected >= 2 part path")
|
||||||
}
|
}
|
||||||
reservedTargetKey = mk.Key.Path[reservedIndex+1].Unbox().ScalarString()
|
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())
|
arrowhead.Label.MapKey.SetScalar(mk.Value.ScalarBox())
|
||||||
return nil
|
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":
|
case "style":
|
||||||
|
|
@ -770,12 +815,23 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "label":
|
case "label":
|
||||||
|
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) {
|
if inlined(&attrs.Label) {
|
||||||
attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
|
attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if attrs.Label.MapKey != nil {
|
} else if attrs.Label.MapKey != nil {
|
||||||
attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
|
attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -846,7 +902,7 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
||||||
baseAST = boardG.BaseAST
|
baseAST = boardG.BaseAST
|
||||||
}
|
}
|
||||||
|
|
||||||
g2, err := deleteReserved(g, mk)
|
g2, err := deleteReserved(g, boardPath, baseAST, mk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -868,9 +924,15 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imported := IsImportedEdge(baseAST, e)
|
||||||
|
|
||||||
|
if imported {
|
||||||
|
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
||||||
|
appendMapKey(baseAST, mk)
|
||||||
|
} else {
|
||||||
refs := e.References
|
refs := e.References
|
||||||
if len(boardPath) > 0 {
|
if len(boardPath) > 0 {
|
||||||
refs := getWriteableEdgeRefs(e, baseAST)
|
refs := GetWriteableEdgeRefs(e, baseAST)
|
||||||
if len(refs) != len(e.References) {
|
if len(refs) != len(e.References) {
|
||||||
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
||||||
}
|
}
|
||||||
|
|
@ -887,8 +949,11 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
||||||
|
|
||||||
for i := len(e.References) - 1; i >= 0; i-- {
|
for i := len(e.References) - 1; i >= 0; i-- {
|
||||||
ref := e.References[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)
|
deleteEdge(g, ref.Scope, ref.MapKey, ref.MapKeyEdgeIndex)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
edges, ok := obj.FindEdges(mk)
|
edges, ok := obj.FindEdges(mk)
|
||||||
if ok {
|
if ok {
|
||||||
|
|
@ -908,6 +973,7 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
||||||
// NOTE: it only needs to be after the last ref, but perhaps simplest and cleanest to append all nulls at the end
|
// 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)
|
appendMapKey(baseAST, mk)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if len(boardPath) > 0 {
|
if len(boardPath) > 0 {
|
||||||
replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
|
replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
|
||||||
if !replaced {
|
if !replaced {
|
||||||
|
|
@ -918,17 +984,19 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
||||||
return recompile(boardG)
|
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))
|
obj, ok := boardG.Root.HasChild(d2graph.Key(mk.Key))
|
||||||
if !ok {
|
if !ok {
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
imported := IsImported(baseAST, obj)
|
imported := IsImportedObj(baseAST, obj)
|
||||||
|
|
||||||
if imported {
|
if imported {
|
||||||
println(d2format.Format(boardG.AST))
|
|
||||||
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
||||||
appendMapKey(baseAST, mk)
|
appendMapKey(baseAST, mk)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -941,7 +1009,7 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
if len(boardPath) > 0 {
|
if len(boardPath) > 0 {
|
||||||
writeableRefs := getWriteableRefs(obj, baseAST)
|
writeableRefs := GetWriteableRefs(obj, baseAST)
|
||||||
if len(writeableRefs) != len(obj.References) {
|
if len(writeableRefs) != len(obj.References) {
|
||||||
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
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) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1053,7 +1121,7 @@ func renameConflictsToParent(g *d2graph.Graph, key *d2ast.KeyPath) (*d2graph.Gra
|
||||||
var absKeys []*d2ast.KeyPath
|
var absKeys []*d2ast.KeyPath
|
||||||
|
|
||||||
if len(ref.Key.Path)-1 == ref.KeyPathIndex {
|
if len(ref.Key.Path)-1 == ref.KeyPathIndex {
|
||||||
if ref.MapKey.Value.Map == nil {
|
if ref.MapKey == nil || ref.MapKey.Value.Map == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var mapKeys []*d2ast.KeyPath
|
var mapKeys []*d2ast.KeyPath
|
||||||
|
|
@ -1178,7 +1246,7 @@ func renameConflictsToParent(g *d2graph.Graph, key *d2ast.KeyPath) (*d2graph.Gra
|
||||||
return g, nil
|
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
|
targetKey := mk.Key
|
||||||
if len(mk.Edges) == 1 {
|
if len(mk.Edges) == 1 {
|
||||||
if mk.EdgeKey == nil {
|
if mk.EdgeKey == nil {
|
||||||
|
|
@ -1193,10 +1261,17 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
|
||||||
|
|
||||||
var e *d2graph.Edge
|
var e *d2graph.Edge
|
||||||
obj := g.Root
|
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 len(mk.Edges) == 1 {
|
||||||
if mk.Key != nil {
|
if mk.Key != nil {
|
||||||
var ok bool
|
var ok bool
|
||||||
obj, ok = g.Root.HasChild(d2graph.Key(mk.Key))
|
obj, ok = obj.HasChild(d2graph.Key(mk.Key))
|
||||||
if !ok {
|
if !ok {
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
@ -1205,26 +1280,45 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return g, nil
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if !deleted && imported {
|
||||||
|
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
||||||
|
appendMapKey(baseAST, mk)
|
||||||
|
}
|
||||||
return recompile(g)
|
return recompile(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
isStyleKey := false
|
isNestedKey := false
|
||||||
for _, id := range d2graph.Key(targetKey) {
|
imported := false
|
||||||
|
parts := d2graph.Key(targetKey)
|
||||||
|
for i, id := range parts {
|
||||||
_, ok := d2graph.ReservedKeywords[id]
|
_, ok := d2graph.ReservedKeywords[id]
|
||||||
if ok {
|
if ok {
|
||||||
if id == "style" {
|
if id == "style" {
|
||||||
isStyleKey = true
|
isNestedKey = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if isStyleKey {
|
if id == "label" || id == "icon" {
|
||||||
err := deleteObjField(g, obj, id)
|
if i < len(parts)-1 {
|
||||||
|
isNestedKey = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isNestedKey {
|
||||||
|
deleted, err := deleteObjField(g, baseAST, obj, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if !deleted && imported {
|
||||||
|
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
||||||
|
appendMapKey(baseAST, mk)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if id == "near" ||
|
if id == "near" ||
|
||||||
|
|
@ -1235,10 +1329,15 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
|
||||||
id == "left" ||
|
id == "left" ||
|
||||||
id == "top" ||
|
id == "top" ||
|
||||||
id == "link" {
|
id == "link" {
|
||||||
err := deleteObjField(g, obj, id)
|
deleted, err := deleteObjField(g, baseAST, obj, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if !deleted && imported {
|
||||||
|
mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
|
||||||
|
appendMapKey(baseAST, mk)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -1246,59 +1345,84 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("object not found")
|
return nil, fmt.Errorf("object not found")
|
||||||
}
|
}
|
||||||
|
imported = IsImportedObj(baseAST, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
return recompile(g)
|
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++ {
|
for i := 0; i < len(m.Nodes); i++ {
|
||||||
n := m.Nodes[i]
|
n := m.Nodes[i]
|
||||||
if n.MapKey != nil && n.MapKey.Key != nil {
|
if n.MapKey != nil && n.MapKey.Key != nil {
|
||||||
if n.MapKey.Key.Path[0].Unbox().ScalarString() == field {
|
if n.MapKey.Key.Path[0].Unbox().ScalarString() == field {
|
||||||
deleteFromMap(m, n.MapKey)
|
deleteFromMap(m, n.MapKey)
|
||||||
} else if n.MapKey.Key.Path[0].Unbox().ScalarString() == "style" ||
|
} 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() == "source-arrowhead" ||
|
||||||
n.MapKey.Key.Path[0].Unbox().ScalarString() == "target-arrowhead" {
|
n.MapKey.Key.Path[0].Unbox().ScalarString() == "target-arrowhead" {
|
||||||
if n.MapKey.Value.Map != nil {
|
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 {
|
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 {
|
} 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 {
|
for _, ref := range e.References {
|
||||||
// Edge chains can't have fields
|
// Edge chains can't have fields
|
||||||
if len(ref.MapKey.Edges) > 1 {
|
if len(ref.MapKey.Edges) > 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if ref.MapKey.Range.Path != ast.Range.Path {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if ref.MapKey.Value.Map != nil {
|
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 {
|
} 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
|
// 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())
|
objK, err := d2parser.ParseKey(obj.AbsID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
objGK := d2graph.Key(objK)
|
objGK := d2graph.Key(objK)
|
||||||
for _, ref := range obj.References {
|
for _, ref := range obj.References {
|
||||||
if ref.InEdge() {
|
if ref.InEdge() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if ref.Key.Range.Path != ast.Range.Path {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if ref.MapKey.Value.Map != nil {
|
if ref.MapKey.Value.Map != nil {
|
||||||
deleteMapField(ref.MapKey.Value.Map, field)
|
deleteMapField(ref.MapKey.Value.Map, field)
|
||||||
} else if (len(ref.Key.Path) >= 2 &&
|
} 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) ||
|
ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == obj.ID) ||
|
||||||
(len(ref.Key.Path) >= 3 &&
|
(len(ref.Key.Path) >= 3 &&
|
||||||
ref.Key.Path[len(ref.Key.Path)-1].Unbox().ScalarString() == field &&
|
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) {
|
ref.Key.Path[len(ref.Key.Path)-3].Unbox().ScalarString() == obj.ID) {
|
||||||
tmpNodes := make([]d2ast.MapNodeBox, len(ref.Scope.Nodes))
|
tmpNodes := make([]d2ast.MapNodeBox, len(ref.Scope.Nodes))
|
||||||
copy(tmpNodes, ref.Scope.Nodes)
|
copy(tmpNodes, ref.Scope.Nodes)
|
||||||
// If I delete this, will the object still exist?
|
// 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)
|
g2, err := recompile(g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if _, ok := g2.Root.HasChild(objGK); !ok {
|
if _, ok := g2.Root.HasChild(objGK); !ok {
|
||||||
// Nope, so can't delete it, just remove the field then
|
// 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) {
|
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)
|
return recompile(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
prevG, _ := recompile(boardG)
|
prevG, err := recompile(boardG)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
ak := d2graph.Key(mk.Key)
|
ak := d2graph.Key(mk.Key)
|
||||||
ak2 := d2graph.Key(mk2.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 {
|
if len(boardPath) > 0 {
|
||||||
writeableRefs := getWriteableRefs(obj, baseAST)
|
writeableRefs := GetWriteableRefs(obj, baseAST)
|
||||||
if len(writeableRefs) != len(obj.References) {
|
if len(writeableRefs) != len(obj.References) {
|
||||||
return nil, OutsideScopeError{}
|
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 {
|
if len(n.MapKey.Key.Path) == 0 {
|
||||||
continue
|
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" {
|
if n.MapKey.Key.Path[len(n.MapKey.Key.Path)-1].Unbox().ScalarString() == "near" {
|
||||||
k := n.MapKey.Value.ScalarBox().Unbox().ScalarString()
|
k := n.MapKey.Value.ScalarBox().Unbox().ScalarString()
|
||||||
|
if _, ok := d2graph.NearConstants[k]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if strings.EqualFold(k, *from) && to == nil {
|
if strings.EqualFold(k, *from) && to == nil {
|
||||||
deleteFromMap(obj.Map, n.MapKey)
|
deleteFromMap(obj.Map, n.MapKey)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -3122,21 +3263,3 @@ func filterReservedPath(path []*d2ast.StringBox) (filtered []*d2ast.StringBox) {
|
||||||
}
|
}
|
||||||
return
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1177,6 +1177,83 @@ b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b: {style.fill: green}
|
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`),
|
value: go2.Pointer(`diamond`),
|
||||||
|
|
||||||
exp: `x -> y: {target-arrowhead.shape: 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
|
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
|
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
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,11 @@ func GetParentID(g *d2graph.Graph, boardPath []string, absID string) (string, er
|
||||||
return obj.Parent.AbsID(), nil
|
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 {
|
for _, ref := range obj.References {
|
||||||
|
if ref.Key.HasGlob() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if ref.Key.Range.Path != ast.Range.Path {
|
if ref.Key.Range.Path != ast.Range.Path {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -150,6 +153,22 @@ func IsImported(ast *d2ast.Map, obj *d2graph.Object) bool {
|
||||||
return false
|
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 {
|
func GetObj(g *d2graph.Graph, boardPath []string, absID string) *d2graph.Object {
|
||||||
g = GetBoardGraph(g, boardPath)
|
g = GetBoardGraph(g, boardPath)
|
||||||
if g == nil {
|
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))
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,3 +201,59 @@ func (p *execPlugin) PostProcess(ctx context.Context, in []byte) ([]byte, error)
|
||||||
|
|
||||||
return stdout, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,11 @@ type RoutingPlugin interface {
|
||||||
RouteEdges(context.Context, *d2graph.Graph, []*d2graph.Edge) error
|
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.
|
// PluginInfo is the current info information of a plugin.
|
||||||
// note: The two fields Type and Path are not set by the plugin
|
// note: The two fields Type and Path are not set by the plugin
|
||||||
// itself but only in ListPlugins.
|
// itself but only in ListPlugins.
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,12 @@ func Serve(p Plugin) xmain.RunFunc {
|
||||||
return layout(ctx, p, ms)
|
return layout(ctx, p, ms)
|
||||||
case "postprocess":
|
case "postprocess":
|
||||||
return postProcess(ctx, p, ms)
|
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:
|
default:
|
||||||
return xmain.UsageErrorf("unrecognized command: %s", subcmd)
|
return xmain.UsageErrorf("unrecognized command: %s", subcmd)
|
||||||
}
|
}
|
||||||
|
|
@ -137,3 +143,41 @@ func postProcess(ctx context.Context, p Plugin, ms *xmain.State) error {
|
||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -321,17 +321,57 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Connection(r *Runner, connection d2target.Connection, path, attrs string) (string, error) {
|
func Connection(r *Runner, connection d2target.Connection, path, attrs string) (string, error) {
|
||||||
|
animatedClass := ""
|
||||||
|
if connection.Animated {
|
||||||
|
animatedClass = " animated-connection"
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
roughness := 0.5
|
||||||
js := fmt.Sprintf(`node = rc.path("%s", {roughness: %f, seed: 1});`, path, roughness)
|
js := fmt.Sprintf(`node = rc.path("%s", {roughness: %f, seed: 1});`, path, roughness)
|
||||||
paths, err := computeRoughPathData(r, js)
|
paths, err := computeRoughPathData(r, js)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
output := ""
|
output := ""
|
||||||
animatedClass := ""
|
|
||||||
if connection.Animated {
|
|
||||||
animatedClass = " animated-connection"
|
|
||||||
}
|
|
||||||
|
|
||||||
pathEl := d2themes.NewThemableElement("path")
|
pathEl := d2themes.NewThemableElement("path")
|
||||||
pathEl.Fill = color.None
|
pathEl.Fill = color.None
|
||||||
|
|
@ -345,6 +385,7 @@ func Connection(r *Runner, connection d2target.Connection, path, attrs string) (
|
||||||
}
|
}
|
||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO cleanup
|
// TODO cleanup
|
||||||
func Table(r *Runner, shape d2target.Shape) (string, error) {
|
func Table(r *Runner, shape d2target.Shape) (string, error) {
|
||||||
|
|
@ -802,6 +843,13 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW
|
||||||
stroke,
|
stroke,
|
||||||
BG_COLOR,
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-2513870599" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-2513870599" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2513870599 .text-bold {
|
.d2-2513870599 .text-bold {
|
||||||
font-family: "d2-2513870599-font-bold";
|
font-family: "d2-2513870599-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 129 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-2513870599" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-2513870599" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2513870599 .text-bold {
|
.d2-2513870599 .text-bold {
|
||||||
font-family: "d2-2513870599-font-bold";
|
font-family: "d2-2513870599-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 59 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-3148583989 .text-bold {
|
.d2-3148583989 .text-bold {
|
||||||
font-family: "d2-3148583989-font-bold";
|
font-family: "d2-3148583989-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-3148583989 .text-bold {
|
.d2-3148583989 .text-bold {
|
||||||
font-family: "d2-3148583989-font-bold";
|
font-family: "d2-3148583989-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 121 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-327680947 .text-bold {
|
.d2-327680947 .text-bold {
|
||||||
font-family: "d2-327680947-font-bold";
|
font-family: "d2-327680947-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-327680947 .text-bold {
|
.d2-327680947 .text-bold {
|
||||||
font-family: "d2-327680947-font-bold";
|
font-family: "d2-327680947-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-914436609 .text {
|
.d2-914436609 .text {
|
||||||
font-family: "d2-914436609-font-regular";
|
font-family: "d2-914436609-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-914436609 .text {
|
.d2-914436609 .text {
|
||||||
font-family: "d2-914436609-font-regular";
|
font-family: "d2-914436609-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2730605657 .text-mono {
|
.d2-2730605657 .text-mono {
|
||||||
font-family: "d2-2730605657-font-mono";
|
font-family: "d2-2730605657-font-mono";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1467 386"><svg id="d2-svg" class="d2-206057491" width="1467" height="386" viewBox="-101 -101 1467 386"><rect x="-101.000000" y="-101.000000" width="1467.000000" height="386.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1467 386"><svg id="d2-svg" class="d2-206057491" width="1467" height="386" viewBox="-101 -101 1467 386"><rect x="-101.000000" y="-101.000000" width="1467.000000" height="386.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-206057491 .text {
|
.d2-206057491 .text {
|
||||||
font-family: "d2-206057491-font-regular";
|
font-family: "d2-206057491-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2730605657 .text-mono {
|
.d2-2730605657 .text-mono {
|
||||||
font-family: "d2-2730605657-font-mono";
|
font-family: "d2-2730605657-font-mono";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2029734873 .text-bold {
|
.d2-2029734873 .text-bold {
|
||||||
font-family: "d2-2029734873-font-bold";
|
font-family: "d2-2029734873-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2029734873 .text-bold {
|
.d2-2029734873 .text-bold {
|
||||||
font-family: "d2-2029734873-font-bold";
|
font-family: "d2-2029734873-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-341527886 .text-bold {
|
.d2-341527886 .text-bold {
|
||||||
font-family: "d2-341527886-font-bold";
|
font-family: "d2-341527886-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-341527886 .text-bold {
|
.d2-341527886 .text-bold {
|
||||||
font-family: "d2-341527886-font-bold";
|
font-family: "d2-341527886-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 398 285"><svg id="d2-svg" class="d2-1379818723" width="398" height="285" viewBox="-101 -115 398 285"><rect x="-101.000000" y="-115.000000" width="398.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 398 285"><svg id="d2-svg" class="d2-1379818723" width="398" height="285" viewBox="-101 -115 398 285"><rect x="-101.000000" y="-115.000000" width="398.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1379818723 .text-bold {
|
.d2-1379818723 .text-bold {
|
||||||
font-family: "d2-1379818723-font-bold";
|
font-family: "d2-1379818723-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-144203892" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-144203892" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-144203892 .text-bold {
|
.d2-144203892 .text-bold {
|
||||||
font-family: "d2-144203892-font-bold";
|
font-family: "d2-144203892-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1441 721"><svg id="d2-svg" class="d2-819970511" width="1441" height="721" viewBox="-101 -112 1441 721"><rect x="-101.000000" y="-112.000000" width="1441.000000" height="721.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1441 721"><svg id="d2-svg" class="d2-819970511" width="1441" height="721" viewBox="-101 -112 1441 721"><rect x="-101.000000" y="-112.000000" width="1441.000000" height="721.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-819970511 .text-bold {
|
.d2-819970511 .text-bold {
|
||||||
font-family: "d2-819970511-font-bold";
|
font-family: "d2-819970511-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 167 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1052 863"><svg id="d2-svg" class="d2-611371411" width="1052" height="863" viewBox="-61 -1 1052 863"><rect x="-61.000000" y="-1.000000" width="1052.000000" height="863.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1052 863"><svg id="d2-svg" class="d2-611371411" width="1052" height="863" viewBox="-61 -1 1052 863"><rect x="-61.000000" y="-1.000000" width="1052.000000" height="863.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-611371411 .text-mono {
|
.d2-611371411 .text-mono {
|
||||||
font-family: "d2-611371411-font-mono";
|
font-family: "d2-611371411-font-mono";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 922 408"><svg id="d2-svg" class="d2-2864094478" width="922" height="408" viewBox="-91 -141 922 408"><rect x="-91.000000" y="-141.000000" width="922.000000" height="408.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 922 408"><svg id="d2-svg" class="d2-2864094478" width="922" height="408" viewBox="-91 -141 922 408"><rect x="-91.000000" y="-141.000000" width="922.000000" height="408.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2864094478 .text {
|
.d2-2864094478 .text {
|
||||||
font-family: "d2-2864094478-font-regular";
|
font-family: "d2-2864094478-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 337 560"><svg id="d2-svg" class="d2-2874225056" width="337" height="560" viewBox="-89 -89 337 560"><rect x="-89.000000" y="-89.000000" width="337.000000" height="560.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 337 560"><svg id="d2-svg" class="d2-2874225056" width="337" height="560" viewBox="-89 -89 337 560"><rect x="-89.000000" y="-89.000000" width="337.000000" height="560.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2874225056 .text-bold {
|
.d2-2874225056 .text-bold {
|
||||||
font-family: "d2-2874225056-font-bold";
|
font-family: "d2-2874225056-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 676 434"><svg id="d2-svg" class="d2-2558489054" width="676" height="434" viewBox="-101 -101 676 434"><rect x="-101.000000" y="-101.000000" width="676.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 676 434"><svg id="d2-svg" class="d2-2558489054" width="676" height="434" viewBox="-101 -101 676 434"><rect x="-101.000000" y="-101.000000" width="676.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2558489054 .text-bold {
|
.d2-2558489054 .text-bold {
|
||||||
font-family: "d2-2558489054-font-bold";
|
font-family: "d2-2558489054-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1098532122 .text {
|
.d2-1098532122 .text {
|
||||||
font-family: "d2-1098532122-font-regular";
|
font-family: "d2-1098532122-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1098532122 .text {
|
.d2-1098532122 .text {
|
||||||
font-family: "d2-1098532122-font-regular";
|
font-family: "d2-1098532122-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-4290168978 .text-bold {
|
.d2-4290168978 .text-bold {
|
||||||
font-family: "d2-4290168978-font-bold";
|
font-family: "d2-4290168978-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 516 636"><svg id="d2-svg" class="d2-3736831304" width="516" height="636" viewBox="-78 -122 516 636"><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" fill="#947A6D" stroke-width="0" /><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" class="paper-overlay" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 516 636"><svg id="d2-svg" class="d2-3736831304" width="516" height="636" viewBox="-78 -122 516 636"><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" fill="#947A6D" stroke-width="0" /><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" class="paper-overlay" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-3736831304 .text-mono {
|
.d2-3736831304 .text-mono {
|
||||||
font-family: "d2-3736831304-font-mono";
|
font-family: "d2-3736831304-font-mono";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 497 KiB After Width: | Height: | Size: 497 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1192 1156"><svg id="d2-svg" class="d2-1077382347" width="1192" height="1156" viewBox="-106 -157 1192 1156"><rect x="-106.000000" y="-157.000000" width="1192.000000" height="1156.000000" rx="0.000000" stroke="LightSteelBlue" fill="honeydew" stroke-width="0" /><rect x="-101.000000" y="-152.000000" width="1182.000000" height="1146.000000" rx="0.000000" stroke="LightSteelBlue" fill="transparent" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1192 1156"><svg id="d2-svg" class="d2-1077382347" width="1192" height="1156" viewBox="-106 -157 1192 1156"><rect x="-106.000000" y="-157.000000" width="1192.000000" height="1156.000000" rx="0.000000" stroke="LightSteelBlue" fill="honeydew" stroke-width="0" /><rect x="-101.000000" y="-152.000000" width="1182.000000" height="1146.000000" rx="0.000000" stroke="LightSteelBlue" fill="transparent" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1077382347 .text {
|
.d2-1077382347 .text {
|
||||||
font-family: "d2-1077382347-font-regular";
|
font-family: "d2-1077382347-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2504113906 .text {
|
.d2-2504113906 .text {
|
||||||
font-family: "d2-2504113906-font-regular";
|
font-family: "d2-2504113906-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2504113906 .text {
|
.d2-2504113906 .text {
|
||||||
font-family: "d2-2504113906-font-regular";
|
font-family: "d2-2504113906-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 832 1627"><svg id="d2-svg" class="d2-790545213" width="832" height="1627" viewBox="-92 -101 832 1627"><rect x="-92.000000" y="-101.000000" width="832.000000" height="1627.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 832 1627"><svg id="d2-svg" class="d2-790545213" width="832" height="1627" viewBox="-92 -101 832 1627"><rect x="-92.000000" y="-101.000000" width="832.000000" height="1627.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-790545213 .text-mono {
|
.d2-790545213 .text-mono {
|
||||||
font-family: "d2-790545213-font-mono";
|
font-family: "d2-790545213-font-mono";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-103900560 .text {
|
.d2-103900560 .text {
|
||||||
font-family: "d2-103900560-font-regular";
|
font-family: "d2-103900560-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 216 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-103900560 .text {
|
.d2-103900560 .text {
|
||||||
font-family: "d2-103900560-font-regular";
|
font-family: "d2-103900560-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 216 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 477 394"><svg id="d2-svg" class="d2-1237400798" width="477" height="394" viewBox="-101 -101 477 394"><rect x="-101.000000" y="-101.000000" width="477.000000" height="394.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 477 394"><svg id="d2-svg" class="d2-1237400798" width="477" height="394" viewBox="-101 -101 477 394"><rect x="-101.000000" y="-101.000000" width="477.000000" height="394.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1237400798 .text-bold {
|
.d2-1237400798 .text-bold {
|
||||||
font-family: "d2-1237400798-font-bold";
|
font-family: "d2-1237400798-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1431 1588"><svg id="d2-svg" class="d2-4070036272" width="1431" height="1588" viewBox="-192 -70 1431 1588"><rect x="-192.000000" y="-70.000000" width="1431" height="1588" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1431 1588"><svg id="d2-svg" class="d2-4070036272" width="1431" height="1588" viewBox="-192 -70 1431 1588"><rect x="-192.000000" y="-70.000000" width="1431" height="1588" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-4070036272 .text {
|
.d2-4070036272 .text {
|
||||||
font-family: "d2-4070036272-font-regular";
|
font-family: "d2-4070036272-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 677 KiB After Width: | Height: | Size: 677 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 407"><svg id="d2-svg" class="d2-1118191387" width="304" height="407" viewBox="-101 -118 304 407"><rect x="-101.000000" y="-118.000000" width="304" height="407" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 407"><svg id="d2-svg" class="d2-1118191387" width="304" height="407" viewBox="-101 -118 304 407"><rect x="-101.000000" y="-118.000000" width="304" height="407" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 657 KiB After Width: | Height: | Size: 657 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-2990259904" width="564" height="682" viewBox="-101 -118 564 682"><rect x="-101.000000" y="-118.000000" width="564" height="682" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-2990259904" width="564" height="682" viewBox="-101 -118 564 682"><rect x="-101.000000" y="-118.000000" width="564" height="682" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 662 KiB After Width: | Height: | Size: 662 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-3058966282" width="564" height="682" viewBox="-101 -118 564 682"><rect x="-101.000000" y="-118.000000" width="564" height="682" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-3058966282" width="564" height="682" viewBox="-101 -118 564 682"><rect x="-101.000000" y="-118.000000" width="564" height="682" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 662 KiB After Width: | Height: | Size: 662 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-3026443247" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" fill="PaleVioletRed" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-3026443247" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" fill="PaleVioletRed" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 661 KiB After Width: | Height: | Size: 661 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-2257413360" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-2257413360" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 661 KiB After Width: | Height: | Size: 661 KiB |
|
|
@ -549,6 +549,7 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
|
||||||
srcAdj, dstAdj := getArrowheadAdjustments(connection, idToShape)
|
srcAdj, dstAdj := getArrowheadAdjustments(connection, idToShape)
|
||||||
path := pathData(connection, srcAdj, dstAdj)
|
path := pathData(connection, srcAdj, dstAdj)
|
||||||
mask := fmt.Sprintf(`mask="url(#%s)"`, labelMaskID)
|
mask := fmt.Sprintf(`mask="url(#%s)"`, labelMaskID)
|
||||||
|
|
||||||
if sketchRunner != nil {
|
if sketchRunner != nil {
|
||||||
out, err := d2sketch.Connection(sketchRunner, connection, path, mask)
|
out, err := d2sketch.Connection(sketchRunner, connection, path, mask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -568,6 +569,34 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
|
||||||
animatedClass = " animated-connection"
|
animatedClass = " animated-connection"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If connection is animated and bidirectional
|
||||||
|
if connection.Animated && ((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 = fmt.Sprintf("%s%s", markerStart, mask)
|
||||||
|
fmt.Fprint(writer, pathEl1.Render())
|
||||||
|
|
||||||
|
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 = fmt.Sprintf("%s%s", markerEnd, mask)
|
||||||
|
fmt.Fprint(writer, pathEl2.Render())
|
||||||
|
} else {
|
||||||
pathEl := d2themes.NewThemableElement("path")
|
pathEl := d2themes.NewThemableElement("path")
|
||||||
pathEl.D = path
|
pathEl.D = path
|
||||||
pathEl.Fill = color.None
|
pathEl.Fill = color.None
|
||||||
|
|
@ -577,6 +606,7 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
|
||||||
pathEl.Attributes = fmt.Sprintf("%s%s%s", markerStart, markerEnd, mask)
|
pathEl.Attributes = fmt.Sprintf("%s%s%s", markerStart, markerEnd, mask)
|
||||||
fmt.Fprint(writer, pathEl.Render())
|
fmt.Fprint(writer, pathEl.Render())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if connection.Label != "" {
|
if connection.Label != "" {
|
||||||
fontClass := "text"
|
fontClass := "text"
|
||||||
|
|
@ -588,6 +618,9 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
|
||||||
} else if connection.Italic {
|
} else if connection.Italic {
|
||||||
fontClass += "-italic"
|
fontClass += "-italic"
|
||||||
}
|
}
|
||||||
|
if connection.Underline {
|
||||||
|
fontClass += " text-underline"
|
||||||
|
}
|
||||||
if connection.Fill != color.Empty {
|
if connection.Fill != color.Empty {
|
||||||
rectEl := d2themes.NewThemableElement("rect")
|
rectEl := d2themes.NewThemableElement("rect")
|
||||||
rectEl.X, rectEl.Y = labelTL.X, labelTL.Y
|
rectEl.X, rectEl.Y = labelTL.X, labelTL.Y
|
||||||
|
|
@ -1033,7 +1066,7 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
fmt.Fprint(writer, el.Render())
|
fmt.Fprint(writer, el.Render())
|
||||||
|
|
||||||
// TODO should standardize "" to rectangle
|
// TODO should standardize "" to rectangle
|
||||||
case d2target.ShapeRectangle, d2target.ShapeSequenceDiagram, "":
|
case d2target.ShapeRectangle, d2target.ShapeSequenceDiagram, d2target.ShapeHierarchy, "":
|
||||||
borderRadius := math.MaxFloat64
|
borderRadius := math.MaxFloat64
|
||||||
if targetShape.BorderRadius != 0 {
|
if targetShape.BorderRadius != 0 {
|
||||||
borderRadius = float64(targetShape.BorderRadius)
|
borderRadius = float64(targetShape.BorderRadius)
|
||||||
|
|
@ -1210,7 +1243,7 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
// Closes the class=shape
|
// Closes the class=shape
|
||||||
fmt.Fprint(writer, `</g>`)
|
fmt.Fprint(writer, `</g>`)
|
||||||
|
|
||||||
if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage {
|
if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage && targetShape.Opacity != 0 {
|
||||||
iconPosition := label.FromString(targetShape.IconPosition)
|
iconPosition := label.FromString(targetShape.IconPosition)
|
||||||
var box *geo.Box
|
var box *geo.Box
|
||||||
if iconPosition.IsOutside() {
|
if iconPosition.IsOutside() {
|
||||||
|
|
@ -1231,7 +1264,7 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetShape.Label != "" {
|
if targetShape.Label != "" && targetShape.Opacity != 0 {
|
||||||
labelPosition := label.FromString(targetShape.LabelPosition)
|
labelPosition := label.FromString(targetShape.LabelPosition)
|
||||||
var box *geo.Box
|
var box *geo.Box
|
||||||
if labelPosition.IsOutside() {
|
if labelPosition.IsOutside() {
|
||||||
|
|
@ -1367,7 +1400,9 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
if targetShape.FontSize != textmeasure.MarkdownFontSize {
|
if targetShape.FontSize != textmeasure.MarkdownFontSize {
|
||||||
styles = append(styles, fmt.Sprintf("font-size:%vpx", targetShape.FontSize))
|
styles = append(styles, fmt.Sprintf("font-size:%vpx", targetShape.FontSize))
|
||||||
}
|
}
|
||||||
|
if targetShape.Fill != "" && targetShape.Fill != "transparent" {
|
||||||
|
styles = append(styles, fmt.Sprintf(`background-color:%s`, targetShape.Fill))
|
||||||
|
}
|
||||||
if !color.IsThemeColor(targetShape.Color) {
|
if !color.IsThemeColor(targetShape.Color) {
|
||||||
styles = append(styles, fmt.Sprintf(`color:%s`, targetShape.Color))
|
styles = append(styles, fmt.Sprintf(`color:%s`, targetShape.Color))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-2513870599" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1400 710"><svg id="d2-svg" class="d2-2513870599" width="1400" height="710" viewBox="-101 -101 1400 710"><rect x="-101.000000" y="-101.000000" width="1400.000000" height="710.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2513870599 .text-bold {
|
.d2-2513870599 .text-bold {
|
||||||
font-family: "d2-2513870599-font-bold";
|
font-family: "d2-2513870599-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2916329547 .text {
|
.d2-2916329547 .text {
|
||||||
font-family: "d2-2916329547-font-regular";
|
font-family: "d2-2916329547-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-3148583989 .text-bold {
|
.d2-3148583989 .text-bold {
|
||||||
font-family: "d2-3148583989-font-bold";
|
font-family: "d2-3148583989-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-327680947 .text-bold {
|
.d2-327680947 .text-bold {
|
||||||
font-family: "d2-327680947-font-bold";
|
font-family: "d2-327680947-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-914436609 .text {
|
.d2-914436609 .text {
|
||||||
font-family: "d2-914436609-font-regular";
|
font-family: "d2-914436609-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2730605657 .text-mono {
|
.d2-2730605657 .text-mono {
|
||||||
font-family: "d2-2730605657-font-mono";
|
font-family: "d2-2730605657-font-mono";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 985 417"><svg id="d2-svg" class="d2-1533752388" width="985" height="417" viewBox="-101 -101 985 417"><rect x="-101.000000" y="-101.000000" width="985.000000" height="417.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 985 417"><svg id="d2-svg" class="d2-1533752388" width="985" height="417" viewBox="-101 -101 985 417"><rect x="-101.000000" y="-101.000000" width="985.000000" height="417.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1533752388 .text {
|
.d2-1533752388 .text {
|
||||||
font-family: "d2-1533752388-font-regular";
|
font-family: "d2-1533752388-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2029734873 .text-bold {
|
.d2-2029734873 .text-bold {
|
||||||
font-family: "d2-2029734873-font-bold";
|
font-family: "d2-2029734873-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1098532122 .text {
|
.d2-1098532122 .text {
|
||||||
font-family: "d2-1098532122-font-regular";
|
font-family: "d2-1098532122-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-4290168978 .text-bold {
|
.d2-4290168978 .text-bold {
|
||||||
font-family: "d2-4290168978-font-bold";
|
font-family: "d2-4290168978-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-2504113906 .text {
|
.d2-2504113906 .text {
|
||||||
font-family: "d2-2504113906-font-regular";
|
font-family: "d2-2504113906-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-274840898" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-274840898" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-274840898 .text {
|
.d2-274840898 .text {
|
||||||
font-family: "d2-274840898-font-regular";
|
font-family: "d2-274840898-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
|
@ -313,9 +313,6 @@ func (diagram Diagram) BoundingBox() (topLeft, bottomRight Point) {
|
||||||
|
|
||||||
if targetShape.Label != "" {
|
if targetShape.Label != "" {
|
||||||
labelPosition := label.FromString(targetShape.LabelPosition)
|
labelPosition := label.FromString(targetShape.LabelPosition)
|
||||||
if !labelPosition.IsOutside() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
shapeType := DSL_SHAPE_TO_SHAPE_TYPE[targetShape.Type]
|
shapeType := DSL_SHAPE_TO_SHAPE_TYPE[targetShape.Type]
|
||||||
s := shape.NewShape(shapeType,
|
s := shape.NewShape(shapeType,
|
||||||
|
|
@ -881,6 +878,7 @@ const (
|
||||||
ShapeSQLTable = "sql_table"
|
ShapeSQLTable = "sql_table"
|
||||||
ShapeImage = "image"
|
ShapeImage = "image"
|
||||||
ShapeSequenceDiagram = "sequence_diagram"
|
ShapeSequenceDiagram = "sequence_diagram"
|
||||||
|
ShapeHierarchy = "hierarchy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Shapes = []string{
|
var Shapes = []string{
|
||||||
|
|
@ -907,6 +905,7 @@ var Shapes = []string{
|
||||||
ShapeSQLTable,
|
ShapeSQLTable,
|
||||||
ShapeImage,
|
ShapeImage,
|
||||||
ShapeSequenceDiagram,
|
ShapeSequenceDiagram,
|
||||||
|
ShapeHierarchy,
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsShape(s string) bool {
|
func IsShape(s string) bool {
|
||||||
|
|
@ -974,6 +973,7 @@ var DSL_SHAPE_TO_SHAPE_TYPE = map[string]string{
|
||||||
ShapeSQLTable: shape.TABLE_TYPE,
|
ShapeSQLTable: shape.TABLE_TYPE,
|
||||||
ShapeImage: shape.IMAGE_TYPE,
|
ShapeImage: shape.IMAGE_TYPE,
|
||||||
ShapeSequenceDiagram: shape.SQUARE_TYPE,
|
ShapeSequenceDiagram: shape.SQUARE_TYPE,
|
||||||
|
ShapeHierarchy: shape.SQUARE_TYPE,
|
||||||
}
|
}
|
||||||
|
|
||||||
var SHAPE_TYPE_TO_DSL_SHAPE map[string]string
|
var SHAPE_TYPE_TO_DSL_SHAPE map[string]string
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ func (el *ThemableElement) Render() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
out += " />"
|
out += " />"
|
||||||
if el.FillPattern != "" {
|
if el.FillPattern != "" && el.FillPattern != "none" {
|
||||||
patternEl := el.Copy()
|
patternEl := el.Copy()
|
||||||
patternEl.Fill = ""
|
patternEl.Fill = ""
|
||||||
patternEl.Stroke = ""
|
patternEl.Stroke = ""
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ git submodule update --recursive
|
||||||
|
|
||||||
## Logistics
|
## Logistics
|
||||||
|
|
||||||
- Use Go 1.20.
|
- Use Go 1.22.
|
||||||
- Please sign your commits
|
- Please sign your commits
|
||||||
([https://github.com/terrastruct/d2/pull/557#issuecomment-1367468730](https://github.com/terrastruct/d2/pull/557#issuecomment-1367468730)).
|
([https://github.com/terrastruct/d2/pull/557#issuecomment-1367468730](https://github.com/terrastruct/d2/pull/557#issuecomment-1367468730)).
|
||||||
- D2 uses Issues as TODOs. No auto-closing on staleness.
|
- D2 uses Issues as TODOs. No auto-closing on staleness.
|
||||||
|
|
@ -100,7 +100,7 @@ running:
|
||||||
./ci/e2ereport.sh -delta
|
./ci/e2ereport.sh -delta
|
||||||
```
|
```
|
||||||
|
|
||||||
This gives me a nice HMTL output of what the test expected vs what it got (this was a PR
|
This gives me a nice HTML output of what the test expected vs what it got (this was a PR
|
||||||
fixing multi-byte character labels):
|
fixing multi-byte character labels):
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
232
docs/assets/example.svg
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
|
@ -765,6 +765,18 @@ i used to read
|
||||||
assert.Testdata(t, ".svg", svg)
|
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",
|
name: "renamed-board",
|
||||||
skipCI: true,
|
skipCI: true,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1843626214 .text-bold {
|
.d2-1843626214 .text-bold {
|
||||||
font-family: "d2-1843626214-font-bold";
|
font-family: "d2-1843626214-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 514 665"><svg id="d2-svg" width="514" height="665" viewBox="-206 -166 514 665"><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 514 665"><svg id="d2-svg" width="514" height="665" viewBox="-206 -166 514 665"><style type="text/css"><![CDATA[
|
||||||
.d2-4130279961 .text {
|
.d2-4130279961 .text {
|
||||||
font-family: "d2-4130279961-font-regular";
|
font-family: "d2-4130279961-font-regular";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3109420268" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3109420268" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-3109420268 .text-bold {
|
.d2-3109420268 .text-bold {
|
||||||
font-family: "d2-3109420268-font-bold";
|
font-family: "d2-3109420268-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 305 285"><svg id="d2-svg" class="d2-4088621414" width="305" height="285" viewBox="-101 -118 305 285"><rect x="-101.000000" y="-118.000000" width="305.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 305 285"><svg id="d2-svg" class="d2-4088621414" width="305" height="285" viewBox="-101 -118 305 285"><rect x="-101.000000" y="-118.000000" width="305.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 285"><svg id="d2-svg" class="d2-1416247347" width="304" height="285" viewBox="-101 -118 304 285"><rect x="-101.000000" y="-118.000000" width="304.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 285"><svg id="d2-svg" class="d2-1416247347" width="304" height="285" viewBox="-101 -118 304 285"><rect x="-101.000000" y="-118.000000" width="304.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.appendix-icon {
|
.appendix-icon {
|
||||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1843626214 .text-bold {
|
.d2-1843626214 .text-bold {
|
||||||
font-family: "d2-1843626214-font-bold";
|
font-family: "d2-1843626214-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3054270525" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3054270525" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-3054270525 .text-bold {
|
.d2-3054270525 .text-bold {
|
||||||
font-family: "d2-3054270525-font-bold";
|
font-family: "d2-3054270525-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 368 766"><svg id="d2-svg" width="368" height="766" viewBox="-101 -101 368 766"><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 368 766"><svg id="d2-svg" width="368" height="766" viewBox="-101 -101 368 766"><style type="text/css"><![CDATA[
|
||||||
.d2-1574744994 .text-bold {
|
.d2-1574744994 .text-bold {
|
||||||
font-family: "d2-1574744994-font-bold";
|
font-family: "d2-1574744994-font-bold";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |