Merge branch 'master' into alixander/flag-env-var

This commit is contained in:
Alexander Wang 2022-11-16 16:31:16 -08:00
commit ff800e1564
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
35 changed files with 1788 additions and 195 deletions

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
d2layouts/d2dagrelayout/dagre.js linguist-vendored
d2layouts/d2elklayout/elk.js linguist-vendored
d2renderers/d2svg/github-markdown.css linguist-vendored

View file

@ -1,2 +1,3 @@
<!-- Please title the PR with a scope prefix like cli: performance improvements. --> <!-- Please title the PR with a scope prefix like cli: performance improvements. -->
<!-- Please add screenshots or screencasts for ui/autolayout changes. --> <!-- Please add screenshots or screencasts for ui/autolayout changes. -->
<!-- Remember to update ci/release/changelogs/next.md, the manpage and cli help documentation. -->

View file

@ -20,27 +20,28 @@
<!-- toc --> <!-- toc -->
- [Quickstart (CLI)](#quickstart-cli) - [Quickstart](#quickstart)
* [MacOS](#macos) - [Install](#install)
* [Linux/Windows](#linuxwindows) * [Install script](#install-script)
- [Quickstart (library)](#quickstart-library) * [Install from source](#install-from-source)
- [D2 as a library](#d2-as-a-library)
- [Themes](#themes) - [Themes](#themes)
- [Fonts](#fonts) - [Fonts](#fonts)
- [Export file types](#export-file-types) - [Export file types](#export-file-types)
- [Language tooling](#language-tooling) - [Language tooling](#language-tooling)
- [Layout engine](#layout-engine) - [Plugins](#plugins)
- [Comparison](#comparison) - [Comparison](#comparison)
- [Contributing](#contributing) - [Contributing](#contributing)
- [License](#license) - [License](#license)
- [Dependencies](#dependencies)
- [Related](#related) - [Related](#related)
* [VSCode extension](#vscode-extension) * [VSCode extension](#vscode-extension)
* [Vim extension](#vim-extension) * [Vim extension](#vim-extension)
* [Misc](#misc) * [Misc](#misc)
- [FAQ](#faq)
<!-- tocstop --> <!-- tocstop -->
## Quickstart (CLI) ## Quickstart
The most convenient way to use D2 is to just run it as a CLI executable to The most convenient way to use D2 is to just run it as a CLI executable to
produce SVGs from `.d2` files. produce SVGs from `.d2` files.
@ -55,22 +56,17 @@ d2 --watch in.d2 out.svg
A browser window will open with `out.svg` and live-reload on changes to `in.d2`. A browser window will open with `out.svg` and live-reload on changes to `in.d2`.
### Install from source ## Install
```sh ### Install script
go install oss.terrastruct.com/d2
```
### Install
The recommended way to install is to run our install script, which will figure out the The recommended way to install is to run our install script, which will figure out the
best way to install based on your machine. E.g. if D2 is available through a package best way to install based on your machine.
manager installed, it will use that package manager.
```sh ```sh
# With --dryrun the install script will print the commands it will use # With --dry-run the install script will print the commands it will use
# to install without actually installing so you know what it's going to do. # to install without actually installing so you know what it's going to do.
curl -fsSL https://d2lang.com/install.sh | sh -s -- --dryrun curl -fsSL https://d2lang.com/install.sh | sh -s -- --dry-run
# If things look good, install for real. # If things look good, install for real.
curl -fsSL https://d2lang.com/install.sh | sh -s -- curl -fsSL https://d2lang.com/install.sh | sh -s --
``` ```
@ -83,7 +79,7 @@ and release a docker image.
To uninstall: To uninstall:
```sh ```sh
curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall --dryrun curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall --dry-run
# If things look good, uninstall for real. # If things look good, uninstall for real.
curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall
``` ```
@ -91,7 +87,15 @@ curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall
> warn: Our binary releases aren't fully portable like normal Go binaries due to the C > warn: Our binary releases aren't fully portable like normal Go binaries due to the C
> dependency on v8go for executing dagre. > dependency on v8go for executing dagre.
## Quickstart (library) ### Install from source
Alternatively, you can install from source:
```sh
go install oss.terrastruct.com/d2
```
## D2 as a library
In addition to being a runnable CLI tool, D2 can also be used to produce diagrams from In addition to being a runnable CLI tool, D2 can also be used to produce diagrams from
Go programs. Go programs.
@ -208,10 +212,13 @@ Copyright © 2022 Terrastruct, Inc. Open-source licensed under the Mozilla Publi
[https://github.com/terrastruct/d2-vim](https://github.com/terrastruct/d2-vim) [https://github.com/terrastruct/d2-vim](https://github.com/terrastruct/d2-vim)
### Language docs
[https://github.com/terrastruct/d2-docs](https://github.com/terrastruct/d2-docs)
### Misc ### Misc
- [https://github.com/terrastruct/d2-docs](https://github.com/terrastruct/d2-docs) - [https://github.com/terrastruct/text-to-diagram-site](https://github.com/terrastruct/text-to-diagram-site)
- [https://github.com/terrastruct/text-to-diagram-com](https://github.com/terrastruct/text-to-diagram-com)
## FAQ ## FAQ
@ -221,10 +228,8 @@ Copyright © 2022 Terrastruct, Inc. Open-source licensed under the Mozilla Publi
- Does D2 need a browser to run? - Does D2 need a browser to run?
- No, D2 can run entirely server-side. - No, D2 can run entirely server-side.
- I have a question or need help. - I have a question or need help.
- The best way to get help is to open an Issue, so that it's searchable by others in the - The best way to get help is to ask on [D2 Discord](https://discord.gg/NF6X8K4eDq)
future. If you prefer synchronous or just want to chat, you can pop into the help - I have a feature request, proposal, or bug report.
channel of the [D2 Discord](https://discord.gg/NF6X8K4eDq) as well. - Please open up a Github Issue.
- I have a feature request or proposal.
- D2 uses Github Issues for everything. Just add a "discussion" label to your Issue.
- I have a private inquiry. - I have a private inquiry.
- Please reach out at [hi@d2lang.com](hi@d2lang.com). - Please reach out at [hi@d2lang.com](hi@d2lang.com).

View file

@ -194,7 +194,7 @@ EOF
if ! manpath | grep -qF "$PREFIX/share/man"; then if ! manpath | grep -qF "$PREFIX/share/man"; then
logcat >&2 <<EOF logcat >&2 <<EOF
Extend your \$MANPATH to view d2's manpages: Extend your \$MANPATH to view d2's manpages:
export MANPATH=$PREFIX/share/man\${MANPATH+:\$MANPATH} export MANPATH=$PREFIX/share/man:\$MANPATH
Then run: Then run:
man d2 man d2
EOF EOF

View file

@ -5,7 +5,7 @@ cd -- "$(dirname "$0")/../.."
help() { help() {
cat <<EOF cat <<EOF
usage: $0 [--rebuild] [--local] [--dry-run] [--run=regex] [--host-only] usage: $0 [--rebuild] [--local] [--dry-run] [--run=regex] [--host-only] [--lockfile-force]
$0 builds D2 release archives into ./ci/release/build/<version>/d2-<VERSION>-<OS>-<ARCH>.tar.gz $0 builds D2 release archives into ./ci/release/build/<version>/d2-<VERSION>-<OS>-<ARCH>.tar.gz
@ -35,6 +35,9 @@ Flags:
--version vX.X.X --version vX.X.X
Use to overwrite the version detected from git. Use to overwrite the version detected from git.
--lockfile-force
Forcefully take ownership of remote builder lockfiles.
EOF EOF
} }
@ -71,6 +74,10 @@ main() {
flag_nonemptyarg && shift "$FLAGSHIFT" flag_nonemptyarg && shift "$FLAGSHIFT"
VERSION=$FLAGARG VERSION=$FLAGARG
;; ;;
lockfile-force)
flag_noarg && shift "$FLAGSHIFT"
LOCKFILE_FORCE=1
;;
'') '')
shift "$FLAGSHIFT" shift "$FLAGSHIFT"
break break
@ -118,10 +125,10 @@ build() {
macos) macos)
case $ARCH in case $ARCH in
amd64) amd64)
RHOST=$TSTRUCT_MACOS_AMD64_BUILDER build_rhost_macos REMOTE_HOST=$TSTRUCT_MACOS_AMD64_BUILDER build_remote_macos
;; ;;
arm64) arm64)
RHOST=$TSTRUCT_MACOS_ARM64_BUILDER build_rhost_macos REMOTE_HOST=$TSTRUCT_MACOS_ARM64_BUILDER build_remote_macos
;; ;;
*) *)
warn "no builder for OS=$OS ARCH=$ARCH, building locally..." warn "no builder for OS=$OS ARCH=$ARCH, building locally..."
@ -132,10 +139,10 @@ build() {
linux) linux)
case $ARCH in case $ARCH in
amd64) amd64)
RHOST=$TSTRUCT_LINUX_AMD64_BUILDER build_rhost_linux REMOTE_HOST=$TSTRUCT_LINUX_AMD64_BUILDER build_remote_linux
;; ;;
arm64) arm64)
RHOST=$TSTRUCT_LINUX_ARM64_BUILDER build_rhost_linux REMOTE_HOST=$TSTRUCT_LINUX_ARM64_BUILDER build_remote_linux
;; ;;
*) *)
warn "no builder for OS=$OS ARCH=$ARCH, building locally..." warn "no builder for OS=$OS ARCH=$ARCH, building locally..."
@ -160,10 +167,12 @@ build_local() {
sh_c ./ci/release/_build.sh sh_c ./ci/release/_build.sh
} }
build_rhost_macos() { build_remote_macos() {
sh_c ssh "$RHOST" mkdir -p src sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
sh_c rsync --archive --human-readable --delete ./ "$RHOST:src/d2/" trap unlockfile_ssh EXIT
sh_c ssh -tttt "$RHOST" "DRY_RUN=${DRY_RUN-} \ sh_c ssh "$REMOTE_HOST" mkdir -p src
sh_c rsync --archive --human-readable --delete ./ "$REMOTE_HOST:src/d2/"
sh_c ssh "$REMOTE_HOST" "DRY_RUN=${DRY_RUN-} \
HW_BUILD_DIR=$HW_BUILD_DIR \ HW_BUILD_DIR=$HW_BUILD_DIR \
VERSION=$VERSION \ VERSION=$VERSION \
OS=$OS \ OS=$OS \
@ -173,13 +182,15 @@ TERM=$TERM \
PATH=\\\"/usr/local/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin\\\${PATH+:\\\$PATH}\\\" \ PATH=\\\"/usr/local/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin\\\${PATH+:\\\$PATH}\\\" \
./src/d2/ci/release/_build.sh" ./src/d2/ci/release/_build.sh"
sh_c mkdir -p "$HW_BUILD_DIR" sh_c mkdir -p "$HW_BUILD_DIR"
sh_c rsync --archive --human-readable "$RHOST:src/d2/$ARCHIVE" "$ARCHIVE" sh_c rsync --archive --human-readable "$REMOTE_HOST:src/d2/$ARCHIVE" "$ARCHIVE"
} }
build_rhost_linux() { build_remote_linux() {
sh_c ssh "$RHOST" mkdir -p src sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
sh_c rsync --archive --human-readable --delete ./ "$RHOST:src/d2/" trap unlockfile_ssh EXIT
sh_c ssh -tttt "$RHOST" "DRY_RUN=${DRY_RUN-} \ sh_c ssh "$REMOTE_HOST" mkdir -p src
sh_c rsync --archive --human-readable --delete ./ "$REMOTE_HOST:src/d2/"
sh_c ssh "$REMOTE_HOST" "DRY_RUN=${DRY_RUN-} \
HW_BUILD_DIR=$HW_BUILD_DIR \ HW_BUILD_DIR=$HW_BUILD_DIR \
VERSION=$VERSION \ VERSION=$VERSION \
OS=$OS \ OS=$OS \
@ -188,7 +199,7 @@ ARCHIVE=$ARCHIVE \
TERM=$TERM \ TERM=$TERM \
./src/d2/ci/release/build_docker.sh" ./src/d2/ci/release/build_docker.sh"
sh_c mkdir -p "$HW_BUILD_DIR" sh_c mkdir -p "$HW_BUILD_DIR"
sh_c rsync --archive --human-readable "$RHOST:src/d2/$ARCHIVE" "$ARCHIVE" sh_c rsync --archive --human-readable "$REMOTE_HOST:src/d2/$ARCHIVE" "$ARCHIVE"
} }
ssh() { ssh() {

View file

@ -0,0 +1,61 @@
#!/bin/sh
set -eu
cd -- "$(dirname "$0")/../../.."
. ./ci/sub/lib.sh
help() {
cat <<EOF
usage: $0 [--dry-run] -i keys.pub
$0 copies keys.pub to each builder and then deduplicates its .authorized_keys.
EOF
}
main() {
while :; do
flag_parse "$@"
case "$FLAG" in
h|help)
help
return 0
;;
dry-run)
flag_noarg && shift "$FLAGSHIFT"
DRY_RUN=1
;;
i)
flag_nonemptyarg && shift "$FLAGSHIFT"
KEY_FILE=$FLAGARG
;;
'')
shift "$FLAGSHIFT"
break
;;
*)
flag_errusage "unrecognized flag $FLAGRAW"
;;
esac
done
if [ -z "${KEY_FILE-}" ]; then
echoerr "-i is required"
exit 1
fi
header linux-amd64
REMOTE_HOST=$TSTRUCT_LINUX_AMD64_BUILDER copy_keys
header linux-arm64
REMOTE_HOST=$TSTRUCT_LINUX_ARM64_BUILDER copy_keys
header macos-amd64
REMOTE_HOST=$TSTRUCT_MACOS_AMD64_BUILDER copy_keys
header macos-arm64
REMOTE_HOST=$TSTRUCT_MACOS_ARM64_BUILDER copy_keys
}
copy_keys() {
sh_c ssh-copy-id -fi "$KEY_FILE" "$REMOTE_HOST"
sh_c ssh "$REMOTE_HOST" 'cat .ssh/authorized_keys \| sort -u \> .ssh/authorized_keys.dedup'
sh_c ssh "$REMOTE_HOST" 'cp .ssh/authorized_keys.dedup .ssh/authorized_keys'
sh_c ssh "$REMOTE_HOST" 'rm .ssh/authorized_keys.dedup'
}
main "$@"

View file

@ -41,12 +41,12 @@ main() {
fi fi
if [ -z "${SKIP_CREATE-}" ]; then if [ -z "${SKIP_CREATE-}" ]; then
create_rhosts create_remote_hosts
fi fi
init_rhosts init_remote_hosts
} }
create_rhosts() { create_remote_hosts() {
KEY_NAME=$(aws ec2 describe-key-pairs | jq -r .KeyPairs[0].KeyName) KEY_NAME=$(aws ec2 describe-key-pairs | jq -r .KeyPairs[0].KeyName)
VPC_ID=$(aws ec2 describe-vpcs | jq -r .Vpcs[0].VpcId) VPC_ID=$(aws ec2 describe-vpcs | jq -r .Vpcs[0].VpcId)
@ -77,7 +77,7 @@ create_rhosts() {
| jq -r '.Reservations[].Instances[].State.Name') | jq -r '.Reservations[].Instances[].State.Name')
if [ -z "$state" ]; then if [ -z "$state" ]; then
sh_c aws ec2 run-instances \ sh_c aws ec2 run-instances \
--image-id=ami-0d593311db5abb72b \ --image-id=ami-071e6cafc48327ca2 \
--count=1 \ --count=1 \
--instance-type=t2.small \ --instance-type=t2.small \
--security-groups=ssh \ --security-groups=ssh \
@ -90,8 +90,8 @@ create_rhosts() {
--filters 'Name=instance-state-name,Values=pending,running,stopping,stopped' 'Name=tag:Name,Values=d2-builder-linux-amd64' \ --filters 'Name=instance-state-name,Values=pending,running,stopping,stopped' 'Name=tag:Name,Values=d2-builder-linux-amd64' \
| jq -r '.Reservations[].Instances[].PublicDnsName') | jq -r '.Reservations[].Instances[].PublicDnsName')
if [ -n "$dnsname" ]; then if [ -n "$dnsname" ]; then
log "TSTRUCT_LINUX_AMD64_BUILDER=ec2-user@$dnsname" log "TSTRUCT_LINUX_AMD64_BUILDER=admin@$dnsname"
export TSTRUCT_LINUX_AMD64_BUILDER=ec2-user@$dnsname export TSTRUCT_LINUX_AMD64_BUILDER=admin@$dnsname
break break
fi fi
sleep 5 sleep 5
@ -103,7 +103,7 @@ create_rhosts() {
| jq -r '.Reservations[].Instances[].State.Name') | jq -r '.Reservations[].Instances[].State.Name')
if [ -z "$state" ]; then if [ -z "$state" ]; then
sh_c aws ec2 run-instances \ sh_c aws ec2 run-instances \
--image-id=ami-0efabcf945ffd8831 \ --image-id=ami-0e67506f183e5ab60 \
--count=1 \ --count=1 \
--instance-type=t4g.small \ --instance-type=t4g.small \
--security-groups=ssh \ --security-groups=ssh \
@ -116,8 +116,8 @@ create_rhosts() {
--filters 'Name=instance-state-name,Values=pending,running,stopping,stopped' 'Name=tag:Name,Values=d2-builder-linux-arm64' \ --filters 'Name=instance-state-name,Values=pending,running,stopping,stopped' 'Name=tag:Name,Values=d2-builder-linux-arm64' \
| jq -r '.Reservations[].Instances[].PublicDnsName') | jq -r '.Reservations[].Instances[].PublicDnsName')
if [ -n "$dnsname" ]; then if [ -n "$dnsname" ]; then
log "TSTRUCT_LINUX_ARM64_BUILDER=ec2-user@$dnsname" log "TSTRUCT_LINUX_ARM64_BUILDER=admin@$dnsname"
export TSTRUCT_LINUX_ARM64_BUILDER=ec2-user@$dnsname export TSTRUCT_LINUX_ARM64_BUILDER=admin@$dnsname
break break
fi fi
sleep 5 sleep 5
@ -194,15 +194,15 @@ create_rhosts() {
done done
} }
init_rhosts() { init_remote_hosts() {
header linux-amd64 header linux-amd64
RHOST=$TSTRUCT_LINUX_AMD64_BUILDER init_rhost_linux REMOTE_HOST=$TSTRUCT_LINUX_AMD64_BUILDER init_remote_linux
header linux-arm64 header linux-arm64
RHOST=$TSTRUCT_LINUX_ARM64_BUILDER init_rhost_linux REMOTE_HOST=$TSTRUCT_LINUX_ARM64_BUILDER init_remote_linux
header macos-amd64 header macos-amd64
RHOST=$TSTRUCT_MACOS_AMD64_BUILDER init_rhost_macos REMOTE_HOST=$TSTRUCT_MACOS_AMD64_BUILDER init_remote_macos
header macos-arm64 header macos-arm64
RHOST=$TSTRUCT_MACOS_ARM64_BUILDER init_rhost_macos REMOTE_HOST=$TSTRUCT_MACOS_ARM64_BUILDER init_remote_macos
COLOR=2 header summary COLOR=2 header summary
log "export TSTRUCT_LINUX_AMD64_BUILDER=$TSTRUCT_LINUX_AMD64_BUILDER" log "export TSTRUCT_LINUX_AMD64_BUILDER=$TSTRUCT_LINUX_AMD64_BUILDER"
@ -211,32 +211,53 @@ init_rhosts() {
log "export TSTRUCT_MACOS_ARM64_BUILDER=$TSTRUCT_MACOS_ARM64_BUILDER" log "export TSTRUCT_MACOS_ARM64_BUILDER=$TSTRUCT_MACOS_ARM64_BUILDER"
} }
init_rhost_linux() { init_remote_linux() {
while true; do while true; do
if sh_c ssh "$RHOST" :; then if sh_c ssh "$REMOTE_HOST" :; then
break break
fi fi
sleep 5 sleep 5
done done
sh_c ssh "$RHOST" 'sudo yum upgrade -y'
sh_c ssh "$RHOST" 'sudo yum install -y docker' sh_c ssh "$REMOTE_HOST" sh -s -- <<EOF
sh_c ssh "$RHOST" 'sudo systemctl start docker' set -eux
sh_c ssh "$RHOST" 'sudo systemctl enable docker' export DEBIAN_FRONTEND=noninteractive
sh_c ssh "$RHOST" 'sudo usermod -a -G docker ec2-user'
sh_c ssh "$RHOST" 'sudo reboot' || true sudo -E apt-get update -y
sudo -E apt-get dist-upgrade -y
sudo -E apt-get install -y build-essential rsync
# Docker from https://docs.docker.com/engine/install/debian/
sudo -E apt-get -y install \
ca-certificates \
curl \
gnupg \
lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
\$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo -E apt-get update -y
sudo -E apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo groupadd docker || true
sudo usermod -aG docker \$USER
EOF
sh_c ssh "$REMOTE_HOST" 'sudo reboot' || true
} }
init_rhost_macos() { init_remote_macos() {
while true; do while true; do
if sh_c ssh "$RHOST" :; then if sh_c ssh "$REMOTE_HOST" :; then
break break
fi fi
sleep 5 sleep 5
done done
sh_c ssh "$RHOST" '": | /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""' sh_c ssh "$REMOTE_HOST" '"/bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""'
sh_c ssh "$RHOST" 'PATH="/usr/local/bin:/opt/homebrew/bin:\$PATH" brew update' sh_c ssh "$REMOTE_HOST" 'PATH="/usr/local/bin:/opt/homebrew/bin:\$PATH" brew update'
sh_c ssh "$RHOST" 'PATH="/usr/local/bin:/opt/homebrew/bin:\$PATH" brew upgrade' sh_c ssh "$REMOTE_HOST" 'PATH="/usr/local/bin:/opt/homebrew/bin:\$PATH" brew upgrade'
sh_c ssh "$RHOST" 'PATH="/usr/local/bin:/opt/homebrew/bin:\$PATH" brew install go' sh_c ssh "$REMOTE_HOST" 'PATH="/usr/local/bin:/opt/homebrew/bin:\$PATH" brew install go'
} }
main "$@" main "$@"

View file

@ -1,43 +0,0 @@
#!/bin/sh
set -eu
cd -- "$(dirname "$0")/../../.."
. ./ci/sub/lib.sh
help() {
cat <<EOF
usage: $0 [--dry-run] [...args]
$0 runs ssh-copy-id on each builder.
args are passed to ssh-copy-id directly.
EOF
}
main() {
while :; do
flag_parse "$@"
case "$FLAG" in
h|help)
help
return 0
;;
dry-run)
flag_noarg && shift "$FLAGSHIFT"
DRY_RUN=1
;;
'')
shift "$FLAGSHIFT"
break
;;
*)
flag_errusage "unrecognized flag $FLAGRAW"
;;
esac
done
sh_c ssh-copy-id "$@" "\$TSTRUCT_LINUX_AMD64_BUILDER"
sh_c ssh-copy-id "$@" "\$TSTRUCT_LINUX_ARM64_BUILDER"
sh_c ssh-copy-id "$@" "\$TSTRUCT_MACOS_AMD64_BUILDER"
sh_c ssh-copy-id "$@" "\$TSTRUCT_MACOS_ARM64_BUILDER"
}
main "$@"

46
ci/release/builders/ssh.sh Executable file
View file

@ -0,0 +1,46 @@
#!/bin/sh
set -eu
cd -- "$(dirname "$0")/../../.."
. ./ci/sub/lib.sh
help() {
cat <<EOF
usage: $0 [--dry-run] [--run=regex] ...
Run a command on every builder instance.
EOF
}
main() {
while :; do
flag_parse "$@"
case "$FLAG" in
h|help)
help
return 0
;;
dry-run)
flag_noarg && shift "$FLAGSHIFT"
DRY_RUN=1
;;
run)
flag_reqarg && shift "$FLAGSHIFT"
JOBFILTER="$FLAGARG"
;;
'')
shift "$FLAGSHIFT"
break
;;
*)
flag_errusage "unrecognized flag $FLAGRAW"
;;
esac
done
REMOTE_HOST=$TSTRUCT_LINUX_AMD64_BUILDER; runjob linux-amd64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$TSTRUCT_LINUX_ARM64_BUILDER; runjob linux-arm64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$TSTRUCT_MACOS_AMD64_BUILDER; runjob macos-amd64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$TSTRUCT_MACOS_ARM64_BUILDER; runjob macos-arm64 ssh "$REMOTE_HOST" "$@"
}
main "$@"

View file

@ -6,7 +6,7 @@ For v0.0.99 we focused on X, Y and Z. Enjoy!
#### Improvements 🔧 #### Improvements 🔧
- Improves something or the other #9999 - Add table columns indices in edges between SQL Tables so that layout engines can route exactly between them
#### Bugfixes 🔴 #### Bugfixes 🔴

View file

@ -0,0 +1 @@
As of v0.0.12, D2 is now open-source!

View file

@ -4,14 +4,14 @@ cd -- "$(dirname "$0")/.."
. ./scripts/lib.sh . ./scripts/lib.sh
main() { main() {
if [ ! -e "${PREFIX-}" ]; then if [ -z "${PREFIX-}" ]; then
echoerr "\$PREFIX must be set to a unix prefix directory in which to install d2 like /usr/local" echoerr "\$PREFIX must be set to a unix prefix directory in which to install d2 like /usr/local"
return 1 return 1
fi fi
sh_c mkdir -p "$PREFIX/bin" sh_c mkdir -p "$PREFIX/bin"
sh_c mkdir -p "$PREFIX/share/man/man1"
sh_c install ./bin/d2 "$PREFIX/bin/d2" sh_c install ./bin/d2 "$PREFIX/bin/d2"
sh_c mkdir -p "$PREFIX/share/man/man1"
sh_c install ./man/d2.1 "$PREFIX/share/man/man1" sh_c install ./man/d2.1 "$PREFIX/share/man/man1"
} }

View file

@ -1,5 +1,9 @@
#!/bin/sh #!/bin/sh
if [ -n "${DEBUG-}" ]; then
set -x
fi
rand() { rand() {
seed="$1" seed="$1"
range="$2" range="$2"

View file

@ -4,7 +4,7 @@ cd -- "$(dirname "$0")/.."
. ./scripts/lib.sh . ./scripts/lib.sh
main() { main() {
if [ ! -e "${PREFIX-}" ]; then if [ -z "${PREFIX-}" ]; then
echoerr "\$PREFIX must be set to a unix prefix directory from which to uninstall d2 like /usr/local" echoerr "\$PREFIX must be set to a unix prefix directory from which to uninstall d2 like /usr/local"
return 1 return 1
fi fi

2
ci/sub

@ -1 +1 @@
Subproject commit 670ea5892b60d815f53a52bf31fdb50ef475ee37 Subproject commit df51b90892737ebe9feca3dd982bcdfc7f684834

View file

@ -36,7 +36,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
debugFlag := ms.Opts.Bool("DEBUG", "debug", "d", false, "print debug logs.") debugFlag := ms.Opts.Bool("DEBUG", "debug", "d", false, "print debug logs.")
layoutFlag := ms.Opts.String("D2_LAYOUT", "layout", "l", "dagre", `the layout engine used.`) layoutFlag := ms.Opts.String("D2_LAYOUT", "layout", "l", "dagre", `the layout engine used.`)
themeFlag := ms.Opts.Int64("D2_THEME", "theme", "t", 0, "the diagram theme ID. For a list of available options, see https://oss.terrastruct.com/d2") themeFlag := ms.Opts.Int64("D2_THEME", "theme", "t", 0, "the diagram theme ID. For a list of available options, see https://oss.terrastruct.com/d2")
versionFlag := ms.Opts.Bool("", "version", "v", false, "get the version and check for updates") versionFlag := ms.Opts.Bool("", "version", "v", false, "get the version")
err = ms.Opts.Parse() err = ms.Opts.Parse()
if !errors.Is(err, pflag.ErrHelp) && err != nil { if !errors.Is(err, pflag.ErrHelp) && err != nil {
@ -64,7 +64,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
if len(ms.Opts.Args()) == 0 { if len(ms.Opts.Args()) == 0 {
if versionFlag != nil && *versionFlag { if versionFlag != nil && *versionFlag {
version.CheckVersion(ctx, ms.Log) fmt.Println(version.Version)
return nil return nil
} }
help(ms) help(ms)
@ -72,9 +72,10 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
} else if len(ms.Opts.Args()) >= 3 { } else if len(ms.Opts.Args()) >= 3 {
return xmain.UsageErrorf("too many arguments passed") return xmain.UsageErrorf("too many arguments passed")
} }
if len(ms.Opts.Args()) >= 1 { if len(ms.Opts.Args()) >= 1 {
if ms.Opts.Arg(0) == "version" { if ms.Opts.Arg(0) == "version" {
version.CheckVersion(ctx, ms.Log) fmt.Println(version.Version)
return nil return nil
} }
inputPath = ms.Opts.Arg(0) inputPath = ms.Opts.Arg(0)

View file

@ -1,8 +1,5 @@
// d2ast implements the d2 language's abstract syntax tree. // d2ast implements the d2 language's abstract syntax tree.
// //
// https://github.com/terrastruct/d2-vscode
// https://terrastruct.com/docs/d2/tour/intro/
//
// Special characters to think about in parser: // Special characters to think about in parser:
// # // #
// """ // """

View file

@ -680,12 +680,12 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) {
continue continue
} }
if srcID == absID { if srcID == absID {
// Frontend isn't aware of container IDs.
d2Col.Reference = strings.TrimPrefix(dstID, parentID+".") d2Col.Reference = strings.TrimPrefix(dstID, parentID+".")
relSrc := strings.TrimPrefix(absID, parentID+".") e.SrcTableColumnIndex = new(int)
e.Attributes.Label.Value = fmt.Sprintf("%s %s %s", relSrc, e.ArrowString(), d2Col.Reference) *e.SrcTableColumnIndex = len(obj.SQLTable.Columns)
// removeContainer() will adjust the edge to point to the table and not inside. } else if dstID == absID {
break e.DstTableColumnIndex = new(int)
*e.DstTableColumnIndex = len(obj.SQLTable.Columns)
} }
} }
@ -746,6 +746,14 @@ func flattenContainer(g *d2graph.Graph, obj *d2graph.Object) {
newEdge, _ = g.Root.Connect(e.Src.AbsIDArray(), obj.AbsIDArray(), e.SrcArrow, e.DstArrow, e.Attributes.Label.Value) newEdge, _ = g.Root.Connect(e.Src.AbsIDArray(), obj.AbsIDArray(), e.SrcArrow, e.DstArrow, e.Attributes.Label.Value)
} }
// TODO more attributes // TODO more attributes
if e.SrcTableColumnIndex != nil {
newEdge.SrcTableColumnIndex = new(int)
*newEdge.SrcTableColumnIndex = *e.SrcTableColumnIndex
}
if e.DstTableColumnIndex != nil {
newEdge.DstTableColumnIndex = new(int)
*newEdge.DstTableColumnIndex = *e.DstTableColumnIndex
}
newEdge.Attributes.Label = e.Attributes.Label newEdge.Attributes.Label = e.Attributes.Label
newEdge.References = e.References newEdge.References = e.References
} }

View file

@ -1474,6 +1474,32 @@ b`, g.Objects[0].Attributes.Label.Value)
SVP1.style.3d: true`, SVP1.style.3d: true`,
expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares and rectangles expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares and rectangles
`, `,
}, {
name: "edge_column_index",
text: `src: {
shape: sql_table
id: int
dst_id: int
}
dst: {
shape: sql_table
id: int
name: string
}
dst.id <-> src.dst_id
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
srcIndex := g.Edges[0].SrcTableColumnIndex
if srcIndex == nil || *srcIndex != 0 {
t.Fatalf("expected SrcTableColumnIndex to be 0, got %v", srcIndex)
}
dstIndex := g.Edges[0].DstTableColumnIndex
if dstIndex == nil || *dstIndex != 1 {
t.Fatalf("expected DstTableColumnIndex to be 1, got %v", dstIndex)
}
},
}, },
} }

View file

@ -1,6 +1,3 @@
// Package d2compiler implements a parser, compiler and autoformatter for the Terrastruct d2 // Package d2compiler implements a parser, compiler and autoformatter for the Terrastruct d2
// diagramming language. // diagramming language.
//
// https://github.com/terrastruct/d2-vscode
// https://terrastruct.com/docs/d2/tour/intro/
package d2compiler package d2compiler

View file

@ -607,6 +607,9 @@ type Edge struct {
MinWidth int `json:"minWidth"` MinWidth int `json:"minWidth"`
MinHeight int `json:"minHeight"` MinHeight int `json:"minHeight"`
SrcTableColumnIndex *int `json:"srcTableColumnIndex,omitempty"`
DstTableColumnIndex *int `json:"dstTableColumnIndex,omitempty"`
LabelDimensions d2target.TextDimensions `json:"label_dimensions"` LabelDimensions d2target.TextDimensions `json:"label_dimensions"`
LabelPosition *string `json:"labelPosition,omitempty"` LabelPosition *string `json:"labelPosition,omitempty"`
LabelPercentage *float64 `json:"labelPercentage,omitempty"` LabelPercentage *float64 `json:"labelPercentage,omitempty"`

View file

@ -0,0 +1,6 @@
dagre.js comes from https://github.com/dagrejs/dagre
Attribution:
MIT License
https://github.com/dagrejs/dagre/blob/master/LICENSE

View file

@ -0,0 +1,6 @@
elk.js comes from https://github.com/kieler/elkjs
Attribution:
EPL License 2.0
https://github.com/kieler/elkjs/blob/master/LICENSE.md

View file

@ -12,7 +12,6 @@ import (
"math" "math"
"rogchap.com/v8go" "rogchap.com/v8go"
v8 "rogchap.com/v8go"
"oss.terrastruct.com/xdefer" "oss.terrastruct.com/xdefer"
@ -104,7 +103,7 @@ func Layout(ctx context.Context, g *d2graph.Graph) (err error) {
}) })
global.Set("setTimeout", setTimeout, v8go.ReadOnly) global.Set("setTimeout", setTimeout, v8go.ReadOnly)
v8ctx := v8.NewContext(iso, global) v8ctx := v8go.NewContext(iso, global)
if _, err := v8ctx.RunScript(elkJS, "elk.js"); err != nil { if _, err := v8ctx.RunScript(elkJS, "elk.js"); err != nil {
return err return err
} }

View file

@ -18,9 +18,6 @@ type Neutral struct {
} }
type ColorPalette struct { type ColorPalette struct {
// So far the palette only contains the colors used in d2 shapes, the full theme includes more colors
// https://www.figma.com/file/n79RbPiHFUTO4PPPdpDu7w/%5BKW%5D-GUI-features?node-id=2268%3A120792
Neutrals Neutral `json:"neutrals"` Neutrals Neutral `json:"neutrals"`
// Base Colors: used for containers // Base Colors: used for containers

View file

@ -831,6 +831,43 @@ a -> md -> b
+setTimeout(seconds int) +setTimeout(seconds int)
} }
`, `,
}, {
name: "sql_tables",
script: `users: {
shape: sql_table
id: int
name: string
email: string
password: string
last_login: datetime
}
products: {
shape: sql_table
id: int
price: decimal
sku: string
name: string
}
orders: {
shape: sql_table
id: int
user_id: int
product_id: int
}
shipments: {
shape: sql_table
id: int
order_id: int
tracking_number: string
status: string
}
users.id <-> orders.user_id
products.id <-> orders.product_id
shipments.order_id <-> orders.id`,
}, },
} }

View file

@ -0,0 +1,396 @@
{
"name": "",
"shapes": [
{
"id": "users",
"type": "sql_table",
"pos": {
"x": 0,
"y": 0
},
"width": 259,
"height": 216,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": "orders.user_id"
},
{
"name": "name",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "email",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "password",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "last_login",
"type": "datetime",
"constraint": "",
"reference": ""
}
],
"label": "users",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 61,
"labelHeight": 36
},
{
"id": "products",
"type": "sql_table",
"pos": {
"x": 319,
"y": 18
},
"width": 290,
"height": 180,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": "orders.product_id"
},
{
"name": "price",
"type": "decimal",
"constraint": "",
"reference": ""
},
{
"name": "sku",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "name",
"type": "string",
"constraint": "",
"reference": ""
}
],
"label": "products",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 99,
"labelHeight": 36
},
{
"id": "orders",
"type": "sql_table",
"pos": {
"x": 357,
"y": 316
},
"width": 215,
"height": 144,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "user_id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "product_id",
"type": "int",
"constraint": "",
"reference": ""
}
],
"label": "orders",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 74,
"labelHeight": 36
},
{
"id": "shipments",
"type": "sql_table",
"pos": {
"x": 669,
"y": 18
},
"width": 293,
"height": 180,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "order_id",
"type": "int",
"constraint": "",
"reference": "orders.id"
},
{
"name": "tracking_number",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "status",
"type": "string",
"constraint": "",
"reference": ""
}
],
"label": "shipments",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 116,
"labelHeight": 36
}
],
"connections": [
{
"id": "(users <-> orders)[0]",
"src": "users",
"srcArrow": "triangle",
"srcLabel": "",
"dst": "orders",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 129.5,
"y": 216
},
{
"x": 129.5,
"y": 256
},
{
"x": 174.9,
"y": 282.55844544095663
},
{
"x": 356.5,
"y": 348.7922272047833
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null
},
{
"id": "(products <-> orders)[0]",
"src": "products",
"srcArrow": "triangle",
"srcLabel": "",
"dst": "orders",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 464,
"y": 198
},
{
"x": 464,
"y": 252.4
},
{
"x": 464,
"y": 276
},
{
"x": 464,
"y": 316
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null
},
{
"id": "(shipments <-> orders)[0]",
"src": "shipments",
"srcArrow": "triangle",
"srcLabel": "",
"dst": "orders",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 815.5,
"y": 198
},
{
"x": 815.5,
"y": 252.4
},
{
"x": 766.7,
"y": 283
},
{
"x": 571.5,
"y": 351
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 335 KiB

View file

@ -0,0 +1,385 @@
{
"name": "",
"shapes": [
{
"id": "users",
"type": "sql_table",
"pos": {
"x": 46,
"y": 412
},
"width": 259,
"height": 216,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": "orders.user_id"
},
{
"name": "name",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "email",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "password",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "last_login",
"type": "datetime",
"constraint": "",
"reference": ""
}
],
"label": "users",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 61,
"labelHeight": 36
},
{
"id": "products",
"type": "sql_table",
"pos": {
"x": 15,
"y": 212
},
"width": 290,
"height": 180,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": "orders.product_id"
},
{
"name": "price",
"type": "decimal",
"constraint": "",
"reference": ""
},
{
"name": "sku",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "name",
"type": "string",
"constraint": "",
"reference": ""
}
],
"label": "products",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 99,
"labelHeight": 36
},
{
"id": "orders",
"type": "sql_table",
"pos": {
"x": 405,
"y": 230
},
"width": 215,
"height": 144,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "user_id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "product_id",
"type": "int",
"constraint": "",
"reference": ""
}
],
"label": "orders",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 74,
"labelHeight": 36
},
{
"id": "shipments",
"type": "sql_table",
"pos": {
"x": 12,
"y": 12
},
"width": 293,
"height": 180,
"level": 1,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"fields": null,
"methods": null,
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "order_id",
"type": "int",
"constraint": "",
"reference": "orders.id"
},
{
"name": "tracking_number",
"type": "string",
"constraint": "",
"reference": ""
},
{
"name": "status",
"type": "string",
"constraint": "",
"reference": ""
}
],
"label": "shipments",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 116,
"labelHeight": 36
}
],
"connections": [
{
"id": "(users <-> orders)[0]",
"src": "users",
"srcArrow": "triangle",
"srcLabel": "",
"dst": "orders",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 305,
"y": 520
},
{
"x": 355,
"y": 520
},
{
"x": 355,
"y": 338
},
{
"x": 405,
"y": 338
}
],
"animated": false,
"tooltip": "",
"icon": null
},
{
"id": "(products <-> orders)[0]",
"src": "products",
"srcArrow": "triangle",
"srcLabel": "",
"dst": "orders",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 305,
"y": 302
},
{
"x": 405,
"y": 302
}
],
"animated": false,
"tooltip": "",
"icon": null
},
{
"id": "(shipments <-> orders)[0]",
"src": "shipments",
"srcArrow": "triangle",
"srcLabel": "",
"dst": "orders",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 305,
"y": 102
},
{
"x": 355,
"y": 102
},
{
"x": 355,
"y": 266
},
{
"x": 405,
"y": 266
}
],
"animated": false,
"tooltip": "",
"icon": null
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 335 KiB

6
go.mod
View file

@ -8,7 +8,6 @@ require (
github.com/alecthomas/chroma v0.10.0 github.com/alecthomas/chroma v0.10.0
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/go-github v17.0.0+incompatible
github.com/lucasb-eyer/go-colorful v1.2.0 github.com/lucasb-eyer/go-colorful v1.2.0
github.com/mazznoer/csscolorparser v0.1.3 github.com/mazznoer/csscolorparser v0.1.3
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
@ -21,8 +20,8 @@ require (
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
gonum.org/v1/plot v0.12.0 gonum.org/v1/plot v0.12.0
nhooyr.io/websocket v1.8.7 nhooyr.io/websocket v1.8.7
oss.terrastruct.com/cmdlog v0.0.0-20221025194258-d3fd7e0b8950 oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37
oss.terrastruct.com/diff v1.0.1 oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541
oss.terrastruct.com/xcontext v0.0.0-20221018000442-50fdafb12f4f oss.terrastruct.com/xcontext v0.0.0-20221018000442-50fdafb12f4f
oss.terrastruct.com/xdefer v0.0.0-20221017222355-6f3b6e4d1557 oss.terrastruct.com/xdefer v0.0.0-20221017222355-6f3b6e4d1557
oss.terrastruct.com/xjson v0.0.0-20221018000420-4986731c4c4a oss.terrastruct.com/xjson v0.0.0-20221018000420-4986731c4c4a
@ -40,7 +39,6 @@ require (
github.com/gin-gonic/gin v1.7.7 // indirect github.com/gin-gonic/gin v1.7.7 // indirect
github.com/go-playground/validator/v10 v10.10.0 // indirect github.com/go-playground/validator/v10 v10.10.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.13.6 // indirect

12
go.sum
View file

@ -189,10 +189,6 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -772,10 +768,10 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
oss.terrastruct.com/cmdlog v0.0.0-20221025194258-d3fd7e0b8950 h1:35gU5c1wwHKhXg58F500d6Ev8s+jqQUg4BiDbx2Zr+g= oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37 h1:Xy1JKJHc4hcuwi57s0BvGUY16GjxTtBmLUybsuGDU7E=
oss.terrastruct.com/cmdlog v0.0.0-20221025194258-d3fd7e0b8950/go.mod h1:ROL3yxl2X+S3O+Rls00qdX6aMh+p1dF8IdxDRwDDpsg= oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37/go.mod h1:ROL3yxl2X+S3O+Rls00qdX6aMh+p1dF8IdxDRwDDpsg=
oss.terrastruct.com/diff v1.0.1 h1:WJ0LPXIgj644ne7l9CtDT9sBMDqo1B2/Ir5zdvbxYN8= oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541 h1:I9B1O1IJ6spivIQxbFRZmbhAwVeLwrcQRR1JbYUOvrI=
oss.terrastruct.com/diff v1.0.1/go.mod h1:cRGe5OvyjX7WWKk7CYh73SoS2tEghpTmAY1IPFWbqgE= oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541/go.mod h1:ags2QDy/T6jr69hT6bpmAmhr2H98n9o8Atf3QlUJPiU=
oss.terrastruct.com/xcontext v0.0.0-20221018000442-50fdafb12f4f h1:7voRCwKM7TZkTo9u7hj+uV/zXoVB8czWrTq6MVIh3dg= oss.terrastruct.com/xcontext v0.0.0-20221018000442-50fdafb12f4f h1:7voRCwKM7TZkTo9u7hj+uV/zXoVB8czWrTq6MVIh3dg=
oss.terrastruct.com/xcontext v0.0.0-20221018000442-50fdafb12f4f/go.mod h1:Y0coTLsWwX0q3a+/Ndq797t+vWyxm42T49Ik3bzaDKY= oss.terrastruct.com/xcontext v0.0.0-20221018000442-50fdafb12f4f/go.mod h1:Y0coTLsWwX0q3a+/Ndq797t+vWyxm42T49Ik3bzaDKY=
oss.terrastruct.com/xdefer v0.0.0-20221017222355-6f3b6e4d1557 h1:rPbhJbN1q7B4tnppSPoAMwq0t6Pk5SrQDQ5S6uoNNHg= oss.terrastruct.com/xdefer v0.0.0-20221017222355-6f3b6e4d1557 h1:rPbhJbN1q7B4tnppSPoAMwq0t6Pk5SrQDQ5S6uoNNHg=

View file

@ -628,7 +628,7 @@ EOF
if ! manpath | grep -qF "$PREFIX/share/man"; then if ! manpath | grep -qF "$PREFIX/share/man"; then
logcat >&2 <<EOF logcat >&2 <<EOF
Extend your \$MANPATH to view d2's manpages: Extend your \$MANPATH to view d2's manpages:
export MANPATH=$PREFIX/share/man\${MANPATH+:\$MANPATH} export MANPATH=$PREFIX/share/man:\$MANPATH
Then run: Then run:
man d2 man d2
EOF EOF

View file

@ -1,44 +1,4 @@
package version package version
import (
"context"
"fmt"
"github.com/google/go-github/github"
"oss.terrastruct.com/cmdlog"
)
// Pre-built binaries will have version set during build time. // Pre-built binaries will have version set during build time.
var Version = "master (built from source)" var Version = "master (built from source)"
func CheckVersion(ctx context.Context, logger *cmdlog.Logger) {
fmt.Println(Version)
if Version == "master (built from source)" {
return
}
// Install script uses -v to check the version, we shouldn't be checking for
// updates here...
// https://github.com/terrastruct/d2/issues/49#issuecomment-1313229683
return
logger.Info.Printf("Checking for updates...")
latest, err := getLatestVersion(ctx)
if err != nil {
logger.Debug.Printf("Error reaching Github for latest version: %s", err.Error())
} else if Version != "master" && Version != latest {
logger.Info.Printf("A new version of D2 is available: %s -> %s", Version, latest)
}
}
func getLatestVersion(ctx context.Context) (string, error) {
client := github.NewClient(nil)
rep, _, err := client.Repositories.GetLatestRelease(ctx, "terrastruct", "d2")
if err != nil {
return "", err
}
return *rep.TagName, nil
}

View file

@ -0,0 +1,559 @@
{
"graph": {
"ast": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:0:0-13:0:123",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:0:0-4:1:48",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:0:0-0:3:3",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:0:0-0:3:3",
"value": [
{
"string": "src",
"raw_string": "src"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:5:5-4:0:47",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,1:1:8-1:17:24",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,1:1:8-1:6:13",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,1:1:8-1:6:13",
"value": [
{
"string": "shape",
"raw_string": "shape"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,1:8:15-1:17:24",
"value": [
{
"string": "sql_table",
"raw_string": "sql_table"
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,2:1:26-2:8:33",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,2:1:26-2:3:28",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,2:1:26-2:3:28",
"value": [
{
"string": "id",
"raw_string": "id"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,2:5:30-2:8:33",
"value": [
{
"string": "int",
"raw_string": "int"
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,3:1:35-3:12:46",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,3:1:35-3:7:41",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,3:1:35-3:7:41",
"value": [
{
"string": "dst_id",
"raw_string": "dst_id"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,3:9:43-3:12:46",
"value": [
{
"string": "int",
"raw_string": "int"
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,6:0:50-10:1:99",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,6:0:50-6:3:53",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,6:0:50-6:3:53",
"value": [
{
"string": "dst",
"raw_string": "dst"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,6:5:55-10:0:98",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,7:1:58-7:17:74",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,7:1:58-7:6:63",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,7:1:58-7:6:63",
"value": [
{
"string": "shape",
"raw_string": "shape"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,7:8:65-7:17:74",
"value": [
{
"string": "sql_table",
"raw_string": "sql_table"
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,8:1:76-8:8:83",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,8:1:76-8:3:78",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,8:1:76-8:3:78",
"value": [
{
"string": "id",
"raw_string": "id"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,8:5:80-8:8:83",
"value": [
{
"string": "int",
"raw_string": "int"
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,9:1:85-9:13:97",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,9:1:85-9:5:89",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,9:1:85-9:5:89",
"value": [
{
"string": "name",
"raw_string": "name"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,9:7:91-9:13:97",
"value": [
{
"string": "string",
"raw_string": "string"
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:0:101-12:21:122",
"edges": [
{
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:0:101-12:21:122",
"src": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:0:101-12:7:108",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:0:101-12:3:104",
"value": [
{
"string": "dst",
"raw_string": "dst"
}
]
}
},
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:4:105-12:6:107",
"value": [
{
"string": "id",
"raw_string": "id"
}
]
}
}
]
},
"src_arrow": "<",
"dst": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:10:111-12:21:122",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:11:112-12:14:115",
"value": [
{
"string": "src",
"raw_string": "src"
}
]
}
},
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:15:116-12:21:122",
"value": [
{
"string": "dst_id",
"raw_string": "dst_id"
}
]
}
}
]
},
"dst_arrow": ">"
}
],
"primary": {},
"value": {}
}
}
]
},
"root": {
"id": "",
"id_val": "",
"label_dimensions": {
"width": 0,
"height": 0
},
"attributes": {
"label": {
"value": ""
},
"style": {},
"near_key": null,
"shape": {
"value": ""
}
}
},
"edges": [
{
"index": 0,
"minWidth": 0,
"minHeight": 0,
"srcTableColumnIndex": 0,
"dstTableColumnIndex": 1,
"label_dimensions": {
"width": 0,
"height": 0
},
"isCurve": false,
"src_arrow": true,
"dst_arrow": true,
"references": [
{
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": ""
},
"style": {},
"near_key": null,
"shape": {
"value": ""
}
}
}
],
"objects": [
{
"id": "src",
"id_val": "src",
"label_dimensions": {
"width": 0,
"height": 0
},
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:0:0-0:3:3",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,0:0:0-0:3:3",
"value": [
{
"string": "src",
"raw_string": "src"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
},
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:10:111-12:21:122",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:11:112-12:14:115",
"value": [
{
"string": "src",
"raw_string": "src"
}
]
}
},
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:15:116-12:21:122",
"value": [
{
"string": "dst_id",
"raw_string": "dst_id"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"sql_table": {
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": ""
},
{
"name": "dst_id",
"type": "int",
"constraint": "",
"reference": ""
}
]
},
"attributes": {
"label": {
"value": "src"
},
"style": {},
"near_key": null,
"shape": {
"value": "sql_table"
}
}
},
{
"id": "dst",
"id_val": "dst",
"label_dimensions": {
"width": 0,
"height": 0
},
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,6:0:50-6:3:53",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,6:0:50-6:3:53",
"value": [
{
"string": "dst",
"raw_string": "dst"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
},
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:0:101-12:7:108",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:0:101-12:3:104",
"value": [
{
"string": "dst",
"raw_string": "dst"
}
]
}
},
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/edge_column_index.d2,12:4:105-12:6:107",
"value": [
{
"string": "id",
"raw_string": "id"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"sql_table": {
"columns": [
{
"name": "id",
"type": "int",
"constraint": "",
"reference": "src.dst_id"
},
{
"name": "name",
"type": "string",
"constraint": "",
"reference": ""
}
]
},
"attributes": {
"label": {
"value": "dst"
},
"style": {},
"near_key": null,
"shape": {
"value": "sql_table"
}
}
}
]
},
"err": null
}