Merge branch 'master' into 1421/bottom-scope-special-boards
|
|
@ -228,7 +228,7 @@ let us know and we'll be happy to include it here!
|
|||
- **Mongo to D2**: [https://github.com/novuhq/mongo-to-D2](https://github.com/novuhq/mongo-to-D2)
|
||||
- **Pandoc filter**: [https://github.com/ram02z/d2-filter](https://github.com/ram02z/d2-filter)
|
||||
- **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/b-yp/logseq-d2)
|
||||
- **ent2d2**: [https://github.com/tmc/ent2d2](https://github.com/tmc/ent2d2)
|
||||
|
||||
### Misc
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#### Features 🚀
|
||||
|
||||
- Configure timeout value with D2_TIMEOUT env var. [#1392](https://github.com/terrastruct/d2/pull/1392)
|
||||
|
||||
#### Improvements 🧹
|
||||
|
||||
- Use shape specific sizing for grid containers [#1294](https://github.com/terrastruct/d2/pull/1294)
|
||||
|
|
@ -8,15 +10,12 @@
|
|||
- Watch mode browser uses an error favicon to easily indicate compiler errors. Thanks @sinyo-matu ! [#1240](https://github.com/terrastruct/d2/pull/1240)
|
||||
- Improves grid layout performance when there are many similarly sized shapes. [#1315](https://github.com/terrastruct/d2/pull/1315)
|
||||
- Connections and labels now are adjusted for shapes with `3d` or `multiple`. [#1340](https://github.com/terrastruct/d2/pull/1340)
|
||||
- Display version on CLI help invocation [#1400](https://github.com/terrastruct/d2/pull/1400)
|
||||
- Improved readability of connection labels when they overlap another connection. [#447](https://github.com/terrastruct/d2/pull/447)
|
||||
- Error message when `shape` is given a composite [#1415](https://github.com/terrastruct/d2/pull/1415)
|
||||
- The autoformatter moves board declarations to the bottom of its scope. [#1424](https://github.com/terrastruct/d2/pull/1424)
|
||||
|
||||
#### Bugfixes ⛑️
|
||||
|
||||
- Shadow is cut off when `--pad` is 0. Thank you @LeonardsonCC ! [#1326](https://github.com/terrastruct/d2/pull/1326)
|
||||
- Fixes grid layout overwriting label placements for nested objects. [#1345](https://github.com/terrastruct/d2/pull/1345)
|
||||
- Fixes fonts not rendering correctly on certain platforms. Thanks @mikeday for identifying the solution. [#1356](https://github.com/terrastruct/d2/pull/1356)
|
||||
- Fixes folders not rendering in animations (`--animate-interval`) [#1357](https://github.com/terrastruct/d2/pull/1357)
|
||||
- Fixes panic using reserved keywords as containers [#1358](https://github.com/terrastruct/d2/pull/1358)
|
||||
- When multiple classes are applied changing different attributes of arrowheads, they are
|
||||
all applied instead of only the last one [#1362](https://github.com/terrastruct/d2/pull/1362)
|
||||
- Prevent empty block strings [#1364](https://github.com/terrastruct/d2/pull/1364)
|
||||
- Fixes edge case in compiler using dots in quotes [#1401](https://github.com/terrastruct/d2/pull/1401)
|
||||
- Fixes grid label font size for TALA [#1412](https://github.com/terrastruct/d2/pull/1412)
|
||||
|
|
|
|||
46
ci/release/changelogs/v0.5.0.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
There are three important features that were in the initial design of D2 that have not been done and hold it back from 1.0: globs, imports, and vars. This release brings imports.
|
||||
|
||||
Imports open up a world of possibilities and works beautifully to modularize diagrams. See the new docs to try it out today.
|
||||
|
||||
As usual, many improvements and bug fixes accompany this release. D2 0.5 produces more legible diagrams by masking obstructions (e.g. arrow going through a label), has better error messages to guide you, is faster at certain tasks, and addresses many issues brought by community bug reports.
|
||||
|
||||
#### Features 🚀
|
||||
|
||||
- D2 files have the ability to import from other D2 files. See [docs](https://d2lang.com/tour/imports). [#1371](https://github.com/terrastruct/d2/pull/1371)
|
||||
- `sql_table` alternatively takes an array of constraints instead of being limited to a single one. Thanks @satoqz ! [#1245](https://github.com/terrastruct/d2/pull/1245)
|
||||
|
||||
#### Improvements 🧹
|
||||
|
||||
- Use shape-specific sizing for grid containers [#1294](https://github.com/terrastruct/d2/pull/1294)
|
||||
- Grid diagrams support nested shapes or grid diagrams [#1309](https://github.com/terrastruct/d2/pull/1309)
|
||||
- `grid-gap`, `vertical-gap`, and `horizontal-gap` apply to padding on grid diagrams [#1309](https://github.com/terrastruct/d2/pull/1309)
|
||||
- Watch mode browser uses an error favicon to easily indicate compiler errors. Thanks @sinyo-matu ! [#1240](https://github.com/terrastruct/d2/pull/1240)
|
||||
- Grid layout performance improved when there are many similarly sized shapes [#1315](https://github.com/terrastruct/d2/pull/1315)
|
||||
- Connections and labels are adjusted for shapes with `3d` or `multiple` [#1340](https://github.com/terrastruct/d2/pull/1340)
|
||||
- Constraints in `sql_table` render even if they have no matching abbreviation [#1372](https://github.com/terrastruct/d2/pull/1372)
|
||||
- Constraints in `sql_table` sheds their excessive letter-spacing and is padded from the end consistently [#1372](https://github.com/terrastruct/d2/pull/1372)
|
||||
- Duplicate image URLs in icons are only fetched once [#1373](https://github.com/terrastruct/d2/pull/1373)
|
||||
- In watch mode, images are cached by default across compiles. Can be disabled with flag `--img-cache=0`. [#1373](https://github.com/terrastruct/d2/pull/1373)
|
||||
- Common invalid array separator `,` usage in class arrays returns a helpful error message [#1376](https://github.com/terrastruct/d2/pull/1376)
|
||||
- Invalid `constraint` usage is met with an error message, preventing a common mistake of omitting `shape: sql_table` [#1379](https://github.com/terrastruct/d2/pull/1379)
|
||||
- Connections no longer obscure outside labels [#1381](https://github.com/terrastruct/d2/pull/1381)
|
||||
- Container connections in `dagre` are more balanced [#1384](https://github.com/terrastruct/d2/pull/1384)
|
||||
- Connections that go through shape labels are now masked translucently [#1383](https://github.com/terrastruct/d2/pull/1383)
|
||||
|
||||
#### Bugfixes ⛑️
|
||||
|
||||
- Shadow is no longer cut off when `--pad` is 0. Thank you @LeonardsonCC ! [#1326](https://github.com/terrastruct/d2/pull/1326)
|
||||
- Fixes grid layout overwriting label placements for nested objects [#1345](https://github.com/terrastruct/d2/pull/1345)
|
||||
- Fixes fonts not rendering correctly on certain platforms. Thanks @mikeday for identifying the solution. [#1356](https://github.com/terrastruct/d2/pull/1356)
|
||||
- Fixes folders not rendering in animations (`--animate-interval`) [#1357](https://github.com/terrastruct/d2/pull/1357)
|
||||
- Fixes panic using reserved keywords as containers [#1358](https://github.com/terrastruct/d2/pull/1358)
|
||||
- When multiple classes are change different attributes of arrowheads, they are
|
||||
all applied instead of only the last one [#1362](https://github.com/terrastruct/d2/pull/1362)
|
||||
- Prevent empty block strings [#1364](https://github.com/terrastruct/d2/pull/1364)
|
||||
- Fixes `dagre` mis-aligning a nested shape's connection [#1370](https://github.com/terrastruct/d2/pull/1370)
|
||||
- Fixes a bug in grids sometimes putting a shape on the next row/column [#1380](https://github.com/terrastruct/d2/pull/1380)
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
- `@xyz` is now reserved as a pattern for imports. If you previously had a key that started like that, it must either be renamed or quoted like `"@xyz"`.
|
||||
- Likewise with `...@xyz` (spread operator import)
|
||||
5
ci/release/changelogs/v0.5.1.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
This is a hotfix to 0.5.0, imports weren't working on Windows.
|
||||
|
||||
#### Improvements 🧹
|
||||
|
||||
- Improves compiler's tooltip URL check. [#1390](https://github.com/terrastruct/d2/pull/1390)
|
||||
|
|
@ -103,27 +103,41 @@ Set the diagram layout engine to the passed string. For a list of available opti
|
|||
.Ar layout
|
||||
.Ns .
|
||||
.It Fl b , -bundle Ar true
|
||||
Bundle all assets and layers into the output svg.
|
||||
Bundle all assets and layers into the output svg
|
||||
.Ns .
|
||||
.It Fl -force-appendix Ar false
|
||||
An appendix for tooltips and links is added to PNG exports since they are not interactive. Setting this to true adds an appendix to SVG exports as well
|
||||
.Ns .
|
||||
.It Fl d , -debug
|
||||
Print debug logs.
|
||||
Print debug logs
|
||||
.Ns .
|
||||
.It Fl -img-cache Ar true
|
||||
In watch mode, images used in icons are cached for subsequent compilations. This should be disabled if images might change
|
||||
.Ns .
|
||||
.It Fl -timeout Ar 120
|
||||
The maximum number of seconds that D2 runs for before timing out and exiting. When rendering a large diagram, it is recommended to increase this value
|
||||
.Ns .
|
||||
.It Fl h , -help
|
||||
Print usage information and exit.
|
||||
Print usage information and exit
|
||||
.Ns .
|
||||
.It Fl v , -version
|
||||
Print version information and exit.
|
||||
Print version information and exit
|
||||
.Ns .
|
||||
.El
|
||||
.Sh SUBCOMMANDS
|
||||
.Bl -tag -width Fl
|
||||
.It Ar layout
|
||||
Lists available layout engine options with short help.
|
||||
Lists available layout engine options with short help
|
||||
.Ns .
|
||||
.It Ar layout Op Ar name
|
||||
Display long help for a particular layout engine, including its configuration options.
|
||||
Display long help for a particular layout engine, including its configuration options
|
||||
.Ns .
|
||||
.It Ar themes
|
||||
Lists available themes.
|
||||
Lists available themes
|
||||
.Ns .
|
||||
.It Ar fmt Ar file.d2 ...
|
||||
Format all passed files.
|
||||
Format all passed files
|
||||
.Ns .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr d2plugin-tala 1
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
|
@ -63,6 +64,7 @@ var _ Node = &DoubleQuotedString{}
|
|||
var _ Node = &SingleQuotedString{}
|
||||
var _ Node = &BlockString{}
|
||||
var _ Node = &Substitution{}
|
||||
var _ Node = &Import{}
|
||||
|
||||
var _ Node = &Array{}
|
||||
var _ Node = &Map{}
|
||||
|
|
@ -179,6 +181,10 @@ func (p Position) String() string {
|
|||
return fmt.Sprintf("%d:%d", p.Line+1, p.Column+1)
|
||||
}
|
||||
|
||||
func (p Position) Debug() string {
|
||||
return fmt.Sprintf("%d:%d:%d", p.Line, p.Column, p.Byte)
|
||||
}
|
||||
|
||||
// See docs on Range.
|
||||
func (p Position) MarshalText() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%d:%d:%d", p.Line, p.Column, p.Byte)), nil
|
||||
|
|
@ -256,6 +262,13 @@ func (p Position) Subtract(r rune, byUTF16 bool) Position {
|
|||
return p
|
||||
}
|
||||
|
||||
func (p Position) AdvanceString(s string, byUTF16 bool) Position {
|
||||
for _, r := range s {
|
||||
p = p.Advance(r, byUTF16)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Position) SubtractString(s string, byUTF16 bool) Position {
|
||||
for _, r := range s {
|
||||
p = p.Subtract(r, byUTF16)
|
||||
|
|
@ -277,6 +290,7 @@ var _ MapNode = &Comment{}
|
|||
var _ MapNode = &BlockComment{}
|
||||
var _ MapNode = &Key{}
|
||||
var _ MapNode = &Substitution{}
|
||||
var _ MapNode = &Import{}
|
||||
|
||||
// ArrayNode is implemented by nodes that may be children of Arrays.
|
||||
type ArrayNode interface {
|
||||
|
|
@ -288,6 +302,7 @@ type ArrayNode interface {
|
|||
var _ ArrayNode = &Comment{}
|
||||
var _ ArrayNode = &BlockComment{}
|
||||
var _ ArrayNode = &Substitution{}
|
||||
var _ ArrayNode = &Import{}
|
||||
|
||||
// Value is implemented by nodes that may be values of a key.
|
||||
type Value interface {
|
||||
|
|
@ -334,6 +349,7 @@ func (s *DoubleQuotedString) node() {}
|
|||
func (s *SingleQuotedString) node() {}
|
||||
func (s *BlockString) node() {}
|
||||
func (s *Substitution) node() {}
|
||||
func (i *Import) node() {}
|
||||
func (a *Array) node() {}
|
||||
func (m *Map) node() {}
|
||||
func (k *Key) node() {}
|
||||
|
|
@ -351,6 +367,7 @@ func (s *DoubleQuotedString) Type() string { return "double quoted string" }
|
|||
func (s *SingleQuotedString) Type() string { return "single quoted string" }
|
||||
func (s *BlockString) Type() string { return s.Tag + " block string" }
|
||||
func (s *Substitution) Type() string { return "substitution" }
|
||||
func (i *Import) Type() string { return "import" }
|
||||
func (a *Array) Type() string { return "array" }
|
||||
func (m *Map) Type() string { return "map" }
|
||||
func (k *Key) Type() string { return "map key" }
|
||||
|
|
@ -368,6 +385,7 @@ func (s *DoubleQuotedString) GetRange() Range { return s.Range }
|
|||
func (s *SingleQuotedString) GetRange() Range { return s.Range }
|
||||
func (s *BlockString) GetRange() Range { return s.Range }
|
||||
func (s *Substitution) GetRange() Range { return s.Range }
|
||||
func (i *Import) GetRange() Range { return i.Range }
|
||||
func (a *Array) GetRange() Range { return a.Range }
|
||||
func (m *Map) GetRange() Range { return m.Range }
|
||||
func (k *Key) GetRange() Range { return k.Range }
|
||||
|
|
@ -379,6 +397,7 @@ func (c *Comment) mapNode() {}
|
|||
func (c *BlockComment) mapNode() {}
|
||||
func (k *Key) mapNode() {}
|
||||
func (s *Substitution) mapNode() {}
|
||||
func (i *Import) mapNode() {}
|
||||
|
||||
func (c *Comment) arrayNode() {}
|
||||
func (c *BlockComment) arrayNode() {}
|
||||
|
|
@ -390,6 +409,7 @@ func (s *DoubleQuotedString) arrayNode() {}
|
|||
func (s *SingleQuotedString) arrayNode() {}
|
||||
func (s *BlockString) arrayNode() {}
|
||||
func (s *Substitution) arrayNode() {}
|
||||
func (i *Import) arrayNode() {}
|
||||
func (a *Array) arrayNode() {}
|
||||
func (m *Map) arrayNode() {}
|
||||
|
||||
|
|
@ -402,6 +422,7 @@ func (s *SingleQuotedString) value() {}
|
|||
func (s *BlockString) value() {}
|
||||
func (a *Array) value() {}
|
||||
func (m *Map) value() {}
|
||||
func (i *Import) value() {}
|
||||
|
||||
func (n *Null) scalar() {}
|
||||
func (b *Boolean) scalar() {}
|
||||
|
|
@ -722,11 +743,20 @@ type Substitution struct {
|
|||
Path []*StringBox `json:"path"`
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
Range Range `json:"range"`
|
||||
|
||||
Spread bool `json:"spread"`
|
||||
Pre string `json:"pre"`
|
||||
Path []*StringBox `json:"path"`
|
||||
}
|
||||
|
||||
// MapNodeBox is used to box MapNode for JSON persistence.
|
||||
type MapNodeBox struct {
|
||||
Comment *Comment `json:"comment,omitempty"`
|
||||
BlockComment *BlockComment `json:"block_comment,omitempty"`
|
||||
Substitution *Substitution `json:"substitution,omitempty"`
|
||||
Import *Import `json:"import,omitempty"`
|
||||
MapKey *Key `json:"map_key,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -739,6 +769,8 @@ func MakeMapNodeBox(n MapNode) MapNodeBox {
|
|||
box.BlockComment = n
|
||||
case *Substitution:
|
||||
box.Substitution = n
|
||||
case *Import:
|
||||
box.Import = n
|
||||
case *Key:
|
||||
box.MapKey = n
|
||||
}
|
||||
|
|
@ -753,6 +785,8 @@ func (mb MapNodeBox) Unbox() MapNode {
|
|||
return mb.BlockComment
|
||||
case mb.Substitution != nil:
|
||||
return mb.Substitution
|
||||
case mb.Import != nil:
|
||||
return mb.Import
|
||||
case mb.MapKey != nil:
|
||||
return mb.MapKey
|
||||
default:
|
||||
|
|
@ -777,6 +811,7 @@ type ArrayNodeBox struct {
|
|||
Comment *Comment `json:"comment,omitempty"`
|
||||
BlockComment *BlockComment `json:"block_comment,omitempty"`
|
||||
Substitution *Substitution `json:"substitution,omitempty"`
|
||||
Import *Import `json:"import,omitempty"`
|
||||
Null *Null `json:"null,omitempty"`
|
||||
Boolean *Boolean `json:"boolean,omitempty"`
|
||||
Number *Number `json:"number,omitempty"`
|
||||
|
|
@ -797,6 +832,8 @@ func MakeArrayNodeBox(an ArrayNode) ArrayNodeBox {
|
|||
ab.BlockComment = an
|
||||
case *Substitution:
|
||||
ab.Substitution = an
|
||||
case *Import:
|
||||
ab.Import = an
|
||||
case *Null:
|
||||
ab.Null = an
|
||||
case *Boolean:
|
||||
|
|
@ -827,6 +864,8 @@ func (ab ArrayNodeBox) Unbox() ArrayNode {
|
|||
return ab.BlockComment
|
||||
case ab.Substitution != nil:
|
||||
return ab.Substitution
|
||||
case ab.Import != nil:
|
||||
return ab.Import
|
||||
case ab.Null != nil:
|
||||
return ab.Null
|
||||
case ab.Boolean != nil:
|
||||
|
|
@ -861,6 +900,7 @@ type ValueBox struct {
|
|||
BlockString *BlockString `json:"block_string,omitempty"`
|
||||
Array *Array `json:"array,omitempty"`
|
||||
Map *Map `json:"map,omitempty"`
|
||||
Import *Import `json:"import,omitempty"`
|
||||
}
|
||||
|
||||
func (vb ValueBox) Unbox() Value {
|
||||
|
|
@ -883,6 +923,8 @@ func (vb ValueBox) Unbox() Value {
|
|||
return vb.Array
|
||||
case vb.Map != nil:
|
||||
return vb.Map
|
||||
case vb.Import != nil:
|
||||
return vb.Import
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -909,6 +951,8 @@ func MakeValueBox(v Value) ValueBox {
|
|||
vb.Array = v
|
||||
case *Map:
|
||||
vb.Map = v
|
||||
case *Import:
|
||||
vb.Import = v
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
|
@ -1002,8 +1046,8 @@ type InterpolationBox struct {
|
|||
// & is only special if it begins a key.
|
||||
// - is only special if followed by another - in a key.
|
||||
// ' " and | are only special if they begin an unquoted key or value.
|
||||
var UnquotedKeySpecials = string([]rune{'#', ';', '\n', '\\', '{', '}', '[', ']', '\'', '"', '|', ':', '.', '-', '<', '>', '*', '&', '(', ')'})
|
||||
var UnquotedValueSpecials = string([]rune{'#', ';', '\n', '\\', '{', '}', '[', ']', '\'', '"', '|', '$'})
|
||||
var UnquotedKeySpecials = string([]rune{'#', ';', '\n', '\\', '{', '}', '[', ']', '\'', '"', '|', ':', '.', '-', '<', '>', '*', '&', '(', ')', '@'})
|
||||
var UnquotedValueSpecials = string([]rune{'#', ';', '\n', '\\', '{', '}', '[', ']', '\'', '"', '|', '$', '@'})
|
||||
|
||||
// RawString returns s in a AST String node that can format s in the most aesthetically
|
||||
// pleasing way.
|
||||
|
|
@ -1052,8 +1096,33 @@ func RawString(s string, inKey bool) String {
|
|||
return FlatUnquotedString(s)
|
||||
}
|
||||
|
||||
func RawStringBox(s string, inKey bool) *StringBox {
|
||||
return MakeValueBox(RawString(s, inKey)).StringBox()
|
||||
}
|
||||
|
||||
func hasSurroundingWhitespace(s string) bool {
|
||||
r, _ := utf8.DecodeRuneInString(s)
|
||||
r2, _ := utf8.DecodeLastRuneInString(s)
|
||||
return unicode.IsSpace(r) || unicode.IsSpace(r2)
|
||||
}
|
||||
|
||||
func (s *Substitution) IDA() (ida []string) {
|
||||
for _, el := range s.Path {
|
||||
ida = append(ida, el.Unbox().ScalarString())
|
||||
}
|
||||
return ida
|
||||
}
|
||||
|
||||
func (i *Import) IDA() (ida []string) {
|
||||
for _, el := range i.Path[1:] {
|
||||
ida = append(ida, el.Unbox().ScalarString())
|
||||
}
|
||||
return ida
|
||||
}
|
||||
|
||||
func (i *Import) PathWithPre() string {
|
||||
if len(i.Path) == 0 {
|
||||
return ""
|
||||
}
|
||||
return path.Join(i.Pre, i.Path[0].Unbox().ScalarString())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import (
|
|||
|
||||
"oss.terrastruct.com/d2/d2plugin"
|
||||
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
|
||||
"oss.terrastruct.com/d2/lib/version"
|
||||
)
|
||||
|
||||
func help(ms *xmain.State) {
|
||||
fmt.Fprintf(ms.Stdout, `Usage:
|
||||
fmt.Fprintf(ms.Stdout, `%[1]s %[2]s
|
||||
Usage:
|
||||
%[1]s [--watch=false] [--theme=0] file.d2 [file.svg | file.png]
|
||||
%[1]s layout [name]
|
||||
%[1]s fmt file.d2 ...
|
||||
|
|
@ -29,7 +31,7 @@ Use - to have d2 read from stdin or write to stdout.
|
|||
See man d2 for more detailed docs.
|
||||
|
||||
Flags:
|
||||
%s
|
||||
%[3]s
|
||||
|
||||
Subcommands:
|
||||
%[1]s layout - Lists available layout engine options with short help
|
||||
|
|
@ -40,7 +42,7 @@ Subcommands:
|
|||
See more docs and the source code at https://oss.terrastruct.com/d2.
|
||||
Hosted icons at https://icons.terrastruct.com.
|
||||
Playground runner at https://play.d2lang.com.
|
||||
`, filepath.Base(ms.Name), ms.Opts.Defaults())
|
||||
`, filepath.Base(ms.Name), version.Version, ms.Opts.Defaults())
|
||||
}
|
||||
|
||||
func layoutCmd(ctx context.Context, ms *xmain.State, ps []d2plugin.Plugin) error {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import (
|
|||
"oss.terrastruct.com/d2/lib/png"
|
||||
"oss.terrastruct.com/d2/lib/pptx"
|
||||
"oss.terrastruct.com/d2/lib/textmeasure"
|
||||
timelib "oss.terrastruct.com/d2/lib/time"
|
||||
"oss.terrastruct.com/d2/lib/version"
|
||||
"oss.terrastruct.com/d2/lib/xgif"
|
||||
|
||||
|
|
@ -67,6 +68,10 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imgCacheFlag, err := ms.Opts.Bool("IMG_CACHE", "img-cache", "", true, "in watch mode, images used in icons are cached for subsequent compilations. This should be disabled if images might change.")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layoutFlag := ms.Opts.String("D2_LAYOUT", "layout", "l", "dagre", `the layout engine used`)
|
||||
themeFlag, err := ms.Opts.Int64("D2_THEME", "theme", "t", 0, "the diagram theme ID")
|
||||
if err != nil {
|
||||
|
|
@ -84,6 +89,11 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
timeoutFlag, err := ms.Opts.Int64("D2_TIMEOUT", "timeout", "", 120, "the maximum number of seconds that D2 runs for before timing out and exiting. When rendering a large diagram, it is recommended to increase this value")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
versionFlag, err := ms.Opts.Bool("", "version", "v", false, "get the version")
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -150,9 +160,15 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
|
|||
if *debugFlag {
|
||||
ms.Env.Setenv("DEBUG", "1")
|
||||
}
|
||||
if *imgCacheFlag {
|
||||
ms.Env.Setenv("IMG_CACHE", "1")
|
||||
}
|
||||
if *browserFlag != "" {
|
||||
ms.Env.Setenv("BROWSER", *browserFlag)
|
||||
}
|
||||
if timeoutFlag != nil {
|
||||
os.Setenv("D2_TIMEOUT", fmt.Sprintf("%d", *timeoutFlag))
|
||||
}
|
||||
|
||||
var inputPath string
|
||||
var outputPath string
|
||||
|
|
@ -291,7 +307,7 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
|
|||
return w.run()
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Minute*2)
|
||||
ctx, cancel := timelib.WithTimeout(ctx, time.Minute*2)
|
||||
defer cancel()
|
||||
|
||||
_, written, err := compile(ctx, ms, plugin, renderOpts, fontFamily, *animateIntervalFlag, inputPath, outputPath, *bundleFlag, *forceAppendixFlag, pw.Page)
|
||||
|
|
@ -322,6 +338,7 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, rende
|
|||
Ruler: ruler,
|
||||
ThemeID: renderOpts.ThemeID,
|
||||
FontFamily: fontFamily,
|
||||
InputPath: inputPath,
|
||||
}
|
||||
if renderOpts.Sketch {
|
||||
opts.FontFamily = go2.Pointer(d2fonts.HandDrawn)
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ func (w *watcher) goServe() error {
|
|||
// TODO: Add standard debug/profiling routes
|
||||
m.HandleFunc("/", w.handleRoot)
|
||||
m.Handle("/static/", http.StripPrefix("/static", w.staticFileServer))
|
||||
m.Handle("/watch", xhttp.HandlerFuncAdapter{w.ms.Log, w.handleWatch})
|
||||
m.Handle("/watch", xhttp.HandlerFuncAdapter{Log: w.ms.Log, Func: w.handleWatch})
|
||||
|
||||
s := xhttp.NewServer(w.ms.Log.Warn, xhttp.Log(w.ms.Log, m))
|
||||
w.goFunc(func(ctx context.Context) error {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -21,21 +22,27 @@ import (
|
|||
|
||||
type CompileOptions struct {
|
||||
UTF16 bool
|
||||
// FS is the file system used for resolving imports in the d2 text.
|
||||
// It should correspond to the root path.
|
||||
FS fs.FS
|
||||
}
|
||||
|
||||
func Compile(path string, r io.RuneReader, opts *CompileOptions) (*d2graph.Graph, error) {
|
||||
func Compile(p string, r io.RuneReader, opts *CompileOptions) (*d2graph.Graph, error) {
|
||||
if opts == nil {
|
||||
opts = &CompileOptions{}
|
||||
}
|
||||
|
||||
ast, err := d2parser.Parse(path, r, &d2parser.ParseOptions{
|
||||
ast, err := d2parser.Parse(p, r, &d2parser.ParseOptions{
|
||||
UTF16: opts.UTF16,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ir, err := d2ir.Compile(ast)
|
||||
ir, err := d2ir.Compile(ast, &d2ir.CompileOptions{
|
||||
UTF16: opts.UTF16,
|
||||
FS: opts.FS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -50,7 +57,9 @@ func Compile(path string, r io.RuneReader, opts *CompileOptions) (*d2graph.Graph
|
|||
}
|
||||
|
||||
func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) {
|
||||
c := &compiler{}
|
||||
c := &compiler{
|
||||
err: &d2parser.ParseError{},
|
||||
}
|
||||
|
||||
g := d2graph.NewGraph()
|
||||
g.AST = ast
|
||||
|
|
@ -101,7 +110,7 @@ func (c *compiler) compileBoardsField(g *d2graph.Graph, ir *d2ir.Map, fieldName
|
|||
}
|
||||
g2 := d2graph.NewGraph()
|
||||
g2.Parent = g
|
||||
g2.AST = g.AST
|
||||
g2.AST = f.Map().AST().(*d2ast.Map)
|
||||
c.compileBoard(g2, f.Map())
|
||||
g2.Name = f.Name
|
||||
switch fieldName {
|
||||
|
|
@ -116,7 +125,7 @@ func (c *compiler) compileBoardsField(g *d2graph.Graph, ir *d2ir.Map, fieldName
|
|||
}
|
||||
|
||||
type compiler struct {
|
||||
err d2parser.ParseError
|
||||
err *d2parser.ParseError
|
||||
}
|
||||
|
||||
func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
|
||||
|
|
@ -147,12 +156,31 @@ func (c *compiler) compileMap(obj *d2graph.Object, m *d2ir.Map) {
|
|||
classMap := m.GetClassMap(className)
|
||||
if classMap != nil {
|
||||
c.compileMap(obj, classMap)
|
||||
} else {
|
||||
if strings.Contains(className, ",") {
|
||||
split := strings.Split(className, ",")
|
||||
allFound := true
|
||||
for _, maybeClassName := range split {
|
||||
maybeClassName = strings.TrimSpace(maybeClassName)
|
||||
if m.GetClassMap(maybeClassName) == nil {
|
||||
allFound = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allFound {
|
||||
c.errorf(class.LastRef().AST(), `class "%s" not found. Did you mean to use ";" to separate array items?`, className)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shape := m.GetField("shape")
|
||||
if shape != nil {
|
||||
c.compileField(obj, shape)
|
||||
if shape.Composite != nil {
|
||||
c.errorf(shape.LastPrimaryKey(), "reserved field shape does not accept composite")
|
||||
} else {
|
||||
c.compileField(obj, shape)
|
||||
}
|
||||
}
|
||||
for _, f := range m.Fields {
|
||||
if f.Name == "shape" {
|
||||
|
|
@ -249,17 +277,19 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
|
|||
obj.Map = fr.Context.Key.Value.Map
|
||||
}
|
||||
}
|
||||
scopeObjIDA := d2ir.BoardIDA(fr.Context.ScopeMap)
|
||||
scopeObj := obj.Graph.Root.EnsureChildIDVal(scopeObjIDA)
|
||||
obj.References = append(obj.References, d2graph.Reference{
|
||||
r := d2graph.Reference{
|
||||
Key: fr.KeyPath,
|
||||
KeyPathIndex: fr.KeyPathIndex(),
|
||||
|
||||
MapKey: fr.Context.Key,
|
||||
MapKeyEdgeIndex: fr.Context.EdgeIndex(),
|
||||
Scope: fr.Context.Scope,
|
||||
ScopeObj: scopeObj,
|
||||
})
|
||||
}
|
||||
if fr.Context.ScopeMap != nil {
|
||||
scopeObjIDA := d2graphIDA(d2ir.BoardIDA(fr.Context.ScopeMap))
|
||||
r.ScopeObj = obj.Graph.Root.EnsureChild(scopeObjIDA)
|
||||
}
|
||||
obj.References = append(obj.References, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -310,8 +340,27 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) {
|
|||
|
||||
func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||
if f.Primary() == nil {
|
||||
if f.Composite != nil && !strings.EqualFold(f.Name, "class") {
|
||||
c.errorf(f.LastPrimaryKey(), "reserved field %v does not accept composite", f.Name)
|
||||
if f.Composite != nil {
|
||||
switch f.Name {
|
||||
case "class":
|
||||
if arr, ok := f.Composite.(*d2ir.Array); ok {
|
||||
for _, class := range arr.Values {
|
||||
if scalar, ok := class.(*d2ir.Scalar); ok {
|
||||
attrs.Classes = append(attrs.Classes, scalar.Value.ScalarString())
|
||||
}
|
||||
}
|
||||
}
|
||||
case "constraint":
|
||||
if arr, ok := f.Composite.(*d2ir.Array); ok {
|
||||
for _, constraint := range arr.Values {
|
||||
if scalar, ok := constraint.(*d2ir.Scalar); ok {
|
||||
attrs.Constraint = append(attrs.Constraint, scalar.Value.ScalarString())
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
c.errorf(f.LastPrimaryKey(), "reserved field %v does not accept composite", f.Name)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -412,8 +461,7 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
|
|||
c.errorf(f.LastPrimaryKey(), "constraint value must be a string")
|
||||
return
|
||||
}
|
||||
attrs.Constraint.Value = scalar.ScalarString()
|
||||
attrs.Constraint.MapKey = f.LastPrimaryKey()
|
||||
attrs.Constraint = append(attrs.Constraint, scalar.ScalarString())
|
||||
case "grid-rows":
|
||||
v, err := strconv.Atoi(scalar.ScalarString())
|
||||
if err != nil {
|
||||
|
|
@ -480,23 +528,13 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
|
|||
attrs.HorizontalGap.Value = scalar.ScalarString()
|
||||
attrs.HorizontalGap.MapKey = f.LastPrimaryKey()
|
||||
case "class":
|
||||
if f.Primary() != nil {
|
||||
attrs.Classes = append(attrs.Classes, scalar.ScalarString())
|
||||
} else if f.Composite != nil {
|
||||
if arr, ok := f.Composite.(*d2ir.Array); ok {
|
||||
for _, class := range arr.Values {
|
||||
if scalar, ok := class.(*d2ir.Scalar); ok {
|
||||
attrs.Classes = append(attrs.Classes, scalar.Value.ScalarString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
attrs.Classes = append(attrs.Classes, scalar.ScalarString())
|
||||
case "classes":
|
||||
}
|
||||
|
||||
if attrs.Link != nil && attrs.Tooltip != nil {
|
||||
_, err := url.ParseRequestURI(attrs.Tooltip.Value)
|
||||
if err == nil {
|
||||
u, err := url.ParseRequestURI(attrs.Tooltip.Value)
|
||||
if err == nil && u.Host != "" {
|
||||
c.errorf(scalar, "Tooltip cannot be set to URL when link is also set (for security)")
|
||||
}
|
||||
}
|
||||
|
|
@ -594,15 +632,17 @@ func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
|
|||
|
||||
edge.Label.MapKey = e.LastPrimaryKey()
|
||||
for _, er := range e.References {
|
||||
scopeObjIDA := d2ir.BoardIDA(er.Context.ScopeMap)
|
||||
scopeObj := edge.Src.Graph.Root.EnsureChildIDVal(scopeObjIDA)
|
||||
edge.References = append(edge.References, d2graph.EdgeReference{
|
||||
r := d2graph.EdgeReference{
|
||||
Edge: er.Context.Edge,
|
||||
MapKey: er.Context.Key,
|
||||
MapKeyEdgeIndex: er.Context.EdgeIndex(),
|
||||
Scope: er.Context.Scope,
|
||||
ScopeObj: scopeObj,
|
||||
})
|
||||
}
|
||||
if er.Context.ScopeMap != nil {
|
||||
scopeObjIDA := d2graphIDA(d2ir.BoardIDA(er.Context.ScopeMap))
|
||||
r.ScopeObj = edge.Src.Graph.Root.EnsureChild(scopeObjIDA)
|
||||
}
|
||||
edge.References = append(edge.References, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -784,11 +824,9 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) {
|
|||
typ = ""
|
||||
}
|
||||
d2Col := d2target.SQLColumn{
|
||||
Name: d2target.Text{Label: col.IDVal},
|
||||
Type: d2target.Text{Label: typ},
|
||||
}
|
||||
if col.Constraint.Value != "" {
|
||||
d2Col.Constraint = col.Constraint.Value
|
||||
Name: d2target.Text{Label: col.IDVal},
|
||||
Type: d2target.Text{Label: typ},
|
||||
Constraint: col.Constraint,
|
||||
}
|
||||
obj.SQLTable.Columns = append(obj.SQLTable.Columns, d2Col)
|
||||
}
|
||||
|
|
@ -848,6 +886,10 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
|||
if !in && arrowheadIn {
|
||||
c.errorf(f.LastPrimaryKey(), fmt.Sprintf(`invalid shape, can only set "%s" for arrowheads`, obj.Shape.Value))
|
||||
}
|
||||
case "constraint":
|
||||
if obj.Shape.Value != d2target.ShapeSQLTable {
|
||||
c.errorf(f.LastPrimaryKey(), `"constraint" keyword can only be used in "sql_table" shapes`)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,6 +315,20 @@ containers: {
|
|||
`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/image_children_Steps.d2:4:3: steps is only allowed at a board root`,
|
||||
},
|
||||
{
|
||||
name: "name-with-dot-underscore",
|
||||
text: `A: {
|
||||
_.C
|
||||
}
|
||||
|
||||
"D.E": {
|
||||
_.C
|
||||
}
|
||||
`,
|
||||
assertions: func(t *testing.T, g *d2graph.Graph) {
|
||||
tassert.Equal(t, 3, len(g.Objects))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stroke-width",
|
||||
|
||||
|
|
@ -1505,6 +1519,11 @@ x -> y: {
|
|||
text: `x: {link: https://not-google.com; tooltip: https://google.com}`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/no_url_link_and_url_tooltip_concurrently.d2:1:44: Tooltip cannot be set to URL when link is also set (for security)`,
|
||||
},
|
||||
{
|
||||
name: "url_link_non_url_tooltip_ok",
|
||||
text: `x: {link: https://not-google.com; tooltip: note: url.ParseRequestURI might see this as a URL}`,
|
||||
expErr: ``,
|
||||
},
|
||||
{
|
||||
name: "url_link_and_not_url_tooltip_concurrently",
|
||||
text: `x: {link: https://google.com; tooltip: hello world}`,
|
||||
|
|
@ -2117,9 +2136,7 @@ ok: {
|
|||
label: bar
|
||||
constraint: BIZ
|
||||
}`,
|
||||
assertions: func(t *testing.T, g *d2graph.Graph) {
|
||||
assert.String(t, "bar", g.Objects[0].Label.Value)
|
||||
},
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/constraint_label.d2:3:3: "constraint" keyword can only be used in "sql_table" shapes`,
|
||||
},
|
||||
{
|
||||
name: "invalid_direction",
|
||||
|
|
@ -2170,13 +2187,17 @@ ok: {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "sql-panic",
|
||||
text: `test {
|
||||
shape: sql_table
|
||||
test_id: varchar(64) {constraint: [primary_key, foreign_key]}
|
||||
}
|
||||
`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/sql-panic.d2:3:27: reserved field constraint does not accept composite`,
|
||||
name: "sql-constraints",
|
||||
text: `x: {
|
||||
shape: sql_table
|
||||
a: int {constraint: primary_key}
|
||||
b: int {constraint: [primary_key; foreign_key]}
|
||||
}`,
|
||||
assertions: func(t *testing.T, g *d2graph.Graph) {
|
||||
table := g.Objects[0].SQLTable
|
||||
tassert.Equal(t, []string{"primary_key"}, table.Columns[0].Constraint)
|
||||
tassert.Equal(t, []string{"primary_key", "foreign_key"}, table.Columns[1].Constraint)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wrong_column_index",
|
||||
|
|
@ -2478,6 +2499,23 @@ nostar -> 1star: { class: [path; path2] }
|
|||
tassert.Equal(t, "2", g.Edges[0].Style.StrokeWidth.Value)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "comma-array-class",
|
||||
|
||||
text: `classes: {
|
||||
dragon_ball: {
|
||||
label: ""
|
||||
shape: circle
|
||||
style.fill: orange
|
||||
}
|
||||
path: {
|
||||
label: "then"
|
||||
style.stroke-width: 4
|
||||
}
|
||||
}
|
||||
nostar: { class: [dragon_ball, path] }`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/comma-array-class.d2:12:11: class "dragon_ball, path" not found. Did you mean to use ";" to separate array items?`,
|
||||
},
|
||||
{
|
||||
name: "reordered-classes",
|
||||
text: `classes: {
|
||||
|
|
@ -2576,6 +2614,15 @@ object: {
|
|||
`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/classes-internal-edge.d2:8:3: classes cannot contain an edge`,
|
||||
},
|
||||
{
|
||||
name: "reserved-composite",
|
||||
text: `shape: sequence_diagram {
|
||||
alice -> bob: What does it mean\nto be well-adjusted?
|
||||
bob -> alice: The ability to play bridge or\ngolf as if they were games.
|
||||
}
|
||||
`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/reserved-composite.d2:1:1: reserved field shape does not accept composite`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package d2format
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
|
@ -62,6 +63,8 @@ func (p *printer) node(n d2ast.Node) {
|
|||
p.blockString(n)
|
||||
case *d2ast.Substitution:
|
||||
p.substitution(n)
|
||||
case *d2ast.Import:
|
||||
p._import(n)
|
||||
case *d2ast.Array:
|
||||
p.array(n)
|
||||
case *d2ast.Map:
|
||||
|
|
@ -203,6 +206,25 @@ func (p *printer) substitution(s *d2ast.Substitution) {
|
|||
p.sb.WriteByte('}')
|
||||
}
|
||||
|
||||
func (p *printer) _import(i *d2ast.Import) {
|
||||
if i.Spread {
|
||||
p.sb.WriteString("...")
|
||||
}
|
||||
p.sb.WriteString("@")
|
||||
pre := path.Clean(i.Pre)
|
||||
if pre != "." {
|
||||
p.sb.WriteString(pre)
|
||||
p.sb.WriteRune('/')
|
||||
}
|
||||
if len(i.Path) > 0 {
|
||||
i2 := *i
|
||||
i2.Path = append([]*d2ast.StringBox{}, i.Path...)
|
||||
i2.Path[0] = d2ast.RawStringBox(path.Clean(i.Path[0].Unbox().ScalarString()), true)
|
||||
i = &i2
|
||||
}
|
||||
p.path(i.Path)
|
||||
}
|
||||
|
||||
func (p *printer) array(a *d2ast.Array) {
|
||||
p.sb.WriteByte('[')
|
||||
if !a.Range.OneLine() {
|
||||
|
|
|
|||
|
|
@ -617,6 +617,46 @@ y
|
|||
x <= y
|
||||
`,
|
||||
exp: `x <- = y
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "import/1",
|
||||
in: `
|
||||
x: @file.d2
|
||||
`,
|
||||
exp: `x: @file
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "import/2",
|
||||
in: `
|
||||
x: @file."d2"
|
||||
`,
|
||||
exp: `x: @file."d2"
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "import/3",
|
||||
in: `
|
||||
x: @./file
|
||||
`,
|
||||
exp: `x: @file
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "import/4",
|
||||
in: `
|
||||
x: @../file
|
||||
`,
|
||||
exp: `x: @../file
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "import/4",
|
||||
in: `
|
||||
x: @"x/../file"
|
||||
`,
|
||||
exp: `x: @file
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -132,8 +132,8 @@ type Attributes struct {
|
|||
// TODO: default to ShapeRectangle instead of empty string
|
||||
Shape Scalar `json:"shape"`
|
||||
|
||||
Direction Scalar `json:"direction"`
|
||||
Constraint Scalar `json:"constraint"`
|
||||
Direction Scalar `json:"direction"`
|
||||
Constraint []string `json:"constraint"`
|
||||
|
||||
GridRows *Scalar `json:"gridRows,omitempty"`
|
||||
GridColumns *Scalar `json:"gridColumns,omitempty"`
|
||||
|
|
@ -584,7 +584,8 @@ func (obj *Object) Text() *d2target.MText {
|
|||
}
|
||||
|
||||
if obj.OuterSequenceDiagram() == nil {
|
||||
if obj.IsContainer() && obj.Shape.Value != "text" {
|
||||
// Note: during grid layout when children are temporarily removed `IsContainer` is false
|
||||
if (obj.IsContainer() || obj.IsGridDiagram()) && obj.Shape.Value != "text" {
|
||||
fontSize = obj.Level().LabelSize()
|
||||
}
|
||||
} else {
|
||||
|
|
@ -671,38 +672,6 @@ func (obj *Object) HasChild(ids []string) (*Object, bool) {
|
|||
return child, true
|
||||
}
|
||||
|
||||
// Keep in sync with EnsureChild.
|
||||
func (obj *Object) EnsureChildIDVal(ids []string) *Object {
|
||||
if len(ids) == 0 {
|
||||
return obj
|
||||
}
|
||||
if len(ids) == 1 && ids[0] != "style" {
|
||||
_, ok := ReservedKeywords[ids[0]]
|
||||
if ok {
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
id := ids[0]
|
||||
ids = ids[1:]
|
||||
|
||||
var child *Object
|
||||
for _, ch2 := range obj.ChildrenArray {
|
||||
if ch2.IDVal == id {
|
||||
child = ch2
|
||||
break
|
||||
}
|
||||
}
|
||||
if child == nil {
|
||||
child = obj.newObject(id)
|
||||
}
|
||||
|
||||
if len(ids) >= 1 {
|
||||
return child.EnsureChildIDVal(ids)
|
||||
}
|
||||
return child
|
||||
}
|
||||
|
||||
func (obj *Object) HasEdge(mk *d2ast.Key) (*Edge, bool) {
|
||||
ea, ok := obj.FindEdges(mk)
|
||||
if !ok {
|
||||
|
|
@ -1005,7 +974,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
|
|||
case d2target.ShapeSQLTable:
|
||||
maxNameWidth := 0
|
||||
maxTypeWidth := 0
|
||||
constraintWidth := 0
|
||||
maxConstraintWidth := 0
|
||||
|
||||
colFontSize := d2fonts.FONT_SIZE_L
|
||||
if obj.Style.FontSize != nil {
|
||||
|
|
@ -1032,21 +1001,24 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
|
|||
}
|
||||
c.Type.LabelWidth = typeDims.Width
|
||||
c.Type.LabelHeight = typeDims.Height
|
||||
if maxTypeWidth < typeDims.Width {
|
||||
maxTypeWidth = typeDims.Width
|
||||
}
|
||||
maxTypeWidth = go2.Max(maxTypeWidth, typeDims.Width)
|
||||
|
||||
if c.Constraint != "" {
|
||||
// covers UNQ constraint with padding
|
||||
constraintWidth = 60
|
||||
if l := len(c.Constraint); l > 0 {
|
||||
constraintDims := GetTextDimensions(mtexts, ruler, ctexts[2], fontFamily)
|
||||
if constraintDims == nil {
|
||||
return nil, fmt.Errorf("dimensions for sql_table constraint %#v not found", ctexts[2].Text)
|
||||
}
|
||||
maxConstraintWidth = go2.Max(maxConstraintWidth, constraintDims.Width)
|
||||
}
|
||||
}
|
||||
|
||||
// The rows get padded a little due to header font being larger than row font
|
||||
dims.Height = go2.Max(12, labelDims.Height*(len(obj.SQLTable.Columns)+1))
|
||||
headerWidth := d2target.HeaderPadding + labelDims.Width + d2target.HeaderPadding
|
||||
rowsWidth := d2target.NamePadding + maxNameWidth + d2target.TypePadding + maxTypeWidth + d2target.TypePadding + constraintWidth
|
||||
rowsWidth := d2target.NamePadding + maxNameWidth + d2target.TypePadding + maxTypeWidth + d2target.TypePadding + maxConstraintWidth
|
||||
if maxConstraintWidth != 0 {
|
||||
rowsWidth += d2target.ConstraintPadding
|
||||
}
|
||||
dims.Width = go2.Max(12, go2.Max(headerWidth, rowsWidth))
|
||||
}
|
||||
|
||||
|
|
@ -1608,6 +1580,24 @@ func (g *Graph) Texts() []*d2target.MText {
|
|||
}
|
||||
}
|
||||
|
||||
for _, board := range g.Layers {
|
||||
for _, t := range board.Texts() {
|
||||
texts = appendTextDedup(texts, t)
|
||||
}
|
||||
}
|
||||
|
||||
for _, board := range g.Scenarios {
|
||||
for _, t := range board.Texts() {
|
||||
texts = appendTextDedup(texts, t)
|
||||
}
|
||||
}
|
||||
|
||||
for _, board := range g.Steps {
|
||||
for _, t := range board.Texts() {
|
||||
texts = appendTextDedup(texts, t)
|
||||
}
|
||||
}
|
||||
|
||||
return texts
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import (
|
|||
"oss.terrastruct.com/d2/lib/shape"
|
||||
)
|
||||
|
||||
const MIN_SEGMENT_LEN = 10
|
||||
|
||||
func (obj *Object) MoveWithDescendants(dx, dy float64) {
|
||||
obj.TopLeft.X += dx
|
||||
obj.TopLeft.Y += dy
|
||||
|
|
@ -127,11 +129,23 @@ func (obj *Object) ShiftDescendants(dx, dy float64) {
|
|||
p.Y += dy
|
||||
}
|
||||
} else if isSrc {
|
||||
e.Route[0].X += dx
|
||||
e.Route[0].Y += dy
|
||||
if dx == 0 {
|
||||
e.ShiftStart(dy, false)
|
||||
} else if dy == 0 {
|
||||
e.ShiftStart(dx, true)
|
||||
} else {
|
||||
e.Route[0].X += dx
|
||||
e.Route[0].Y += dy
|
||||
}
|
||||
} else if isDst {
|
||||
e.Route[len(e.Route)-1].X += dx
|
||||
e.Route[len(e.Route)-1].Y += dy
|
||||
if dx == 0 {
|
||||
e.ShiftEnd(dy, false)
|
||||
} else if dy == 0 {
|
||||
e.ShiftEnd(dx, true)
|
||||
} else {
|
||||
e.Route[len(e.Route)-1].X += dx
|
||||
e.Route[len(e.Route)-1].Y += dy
|
||||
}
|
||||
}
|
||||
|
||||
if isSrc || isDst {
|
||||
|
|
@ -141,6 +155,118 @@ func (obj *Object) ShiftDescendants(dx, dy float64) {
|
|||
})
|
||||
}
|
||||
|
||||
// ShiftStart moves the starting point of the route by delta either horizontally or vertically
|
||||
// if subsequent points are in line with the movement, they will be removed (unless it is the last point)
|
||||
// start end
|
||||
// . ├────┼────┼───┼────┼───┤ before
|
||||
// . ├──dx──►
|
||||
// . ├──┼───┼────┼───┤ after
|
||||
func (edge *Edge) ShiftStart(delta float64, isHorizontal bool) {
|
||||
position := func(p *geo.Point) float64 {
|
||||
if isHorizontal {
|
||||
return p.X
|
||||
}
|
||||
return p.Y
|
||||
}
|
||||
|
||||
start := edge.Route[0]
|
||||
next := edge.Route[1]
|
||||
isIncreasing := position(start) < position(next)
|
||||
if isHorizontal {
|
||||
start.X += delta
|
||||
} else {
|
||||
start.Y += delta
|
||||
}
|
||||
|
||||
if isIncreasing == (delta < 0) {
|
||||
// nothing more to do when moving away from the next point
|
||||
return
|
||||
}
|
||||
|
||||
isAligned := func(p *geo.Point) bool {
|
||||
if isHorizontal {
|
||||
return p.Y == start.Y
|
||||
}
|
||||
return p.X == start.X
|
||||
}
|
||||
isPastStart := func(p *geo.Point) bool {
|
||||
if delta > 0 {
|
||||
return position(p) < position(start)
|
||||
} else {
|
||||
return position(p) > position(start)
|
||||
}
|
||||
}
|
||||
|
||||
needsRemoval := false
|
||||
toRemove := make([]bool, len(edge.Route))
|
||||
for i := 1; i < len(edge.Route)-1; i++ {
|
||||
if !isAligned(edge.Route[i]) {
|
||||
break
|
||||
}
|
||||
if isPastStart(edge.Route[i]) {
|
||||
toRemove[i] = true
|
||||
needsRemoval = true
|
||||
}
|
||||
}
|
||||
if needsRemoval {
|
||||
edge.Route = geo.RemovePoints(edge.Route, toRemove)
|
||||
}
|
||||
}
|
||||
|
||||
// ShiftEnd moves the ending point of the route by delta either horizontally or vertically
|
||||
// if prior points are in line with the movement, they will be removed (unless it is the first point)
|
||||
func (edge *Edge) ShiftEnd(delta float64, isHorizontal bool) {
|
||||
position := func(p *geo.Point) float64 {
|
||||
if isHorizontal {
|
||||
return p.X
|
||||
}
|
||||
return p.Y
|
||||
}
|
||||
|
||||
end := edge.Route[len(edge.Route)-1]
|
||||
prev := edge.Route[len(edge.Route)-2]
|
||||
isIncreasing := position(prev) < position(end)
|
||||
if isHorizontal {
|
||||
end.X += delta
|
||||
} else {
|
||||
end.Y += delta
|
||||
}
|
||||
|
||||
if isIncreasing == (delta > 0) {
|
||||
// nothing more to do when moving away from the next point
|
||||
return
|
||||
}
|
||||
|
||||
isAligned := func(p *geo.Point) bool {
|
||||
if isHorizontal {
|
||||
return p.Y == end.Y
|
||||
}
|
||||
return p.X == end.X
|
||||
}
|
||||
isPastEnd := func(p *geo.Point) bool {
|
||||
if delta > 0 {
|
||||
return position(p) < position(end)
|
||||
} else {
|
||||
return position(p) > position(end)
|
||||
}
|
||||
}
|
||||
|
||||
needsRemoval := false
|
||||
toRemove := make([]bool, len(edge.Route))
|
||||
for i := len(edge.Route) - 2; i > 0; i-- {
|
||||
if !isAligned(edge.Route[i]) {
|
||||
break
|
||||
}
|
||||
if isPastEnd(edge.Route[i]) {
|
||||
toRemove[i] = true
|
||||
needsRemoval = true
|
||||
}
|
||||
}
|
||||
if needsRemoval {
|
||||
edge.Route = geo.RemovePoints(edge.Route, toRemove)
|
||||
}
|
||||
}
|
||||
|
||||
// GetModifierElementAdjustments returns width/height adjustments to account for shapes with 3d or multiple
|
||||
func (obj *Object) GetModifierElementAdjustments() (dx, dy float64) {
|
||||
if obj.Is3D() {
|
||||
|
|
@ -189,3 +315,72 @@ func (obj *Object) GetLabelTopLeft() *geo.Point {
|
|||
)
|
||||
return labelTL
|
||||
}
|
||||
|
||||
func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (newStart, newEnd int) {
|
||||
srcShape := edge.Src.ToShape()
|
||||
dstShape := edge.Dst.ToShape()
|
||||
|
||||
// if an edge runs into an outside label, stop the edge at the label instead
|
||||
overlapsOutsideLabel := false
|
||||
if edge.Src.HasLabel() {
|
||||
// assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
|
||||
labelPosition := label.Position(*edge.Src.LabelPosition)
|
||||
if labelPosition.IsOutside() {
|
||||
labelWidth := float64(edge.Src.LabelDimensions.Width)
|
||||
labelHeight := float64(edge.Src.LabelDimensions.Height)
|
||||
labelTL := labelPosition.GetPointOnBox(edge.Src.Box, label.PADDING, labelWidth, labelHeight)
|
||||
|
||||
startingSegment := geo.Segment{Start: points[startIndex+1], End: points[startIndex]}
|
||||
labelBox := geo.NewBox(labelTL, labelWidth, labelHeight)
|
||||
// add left/right padding to box
|
||||
labelBox.TopLeft.X -= label.PADDING
|
||||
labelBox.Width += 2 * label.PADDING
|
||||
if intersections := labelBox.Intersections(startingSegment); len(intersections) > 0 {
|
||||
overlapsOutsideLabel = true
|
||||
// move starting segment to label intersection point
|
||||
points[startIndex] = intersections[0]
|
||||
startingSegment.End = intersections[0]
|
||||
// if the segment becomes too short, just merge it with the next segment
|
||||
if startIndex < len(points) && startingSegment.Length() < MIN_SEGMENT_LEN {
|
||||
points[startIndex+1] = points[startIndex]
|
||||
startIndex++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !overlapsOutsideLabel {
|
||||
// trace the edge to the specific shape's border
|
||||
points[startIndex] = shape.TraceToShapeBorder(srcShape, points[startIndex], points[startIndex+1])
|
||||
}
|
||||
overlapsOutsideLabel = false
|
||||
if edge.Dst.HasLabel() {
|
||||
// assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
|
||||
labelPosition := label.Position(*edge.Dst.LabelPosition)
|
||||
if labelPosition.IsOutside() {
|
||||
labelWidth := float64(edge.Dst.LabelDimensions.Width)
|
||||
labelHeight := float64(edge.Dst.LabelDimensions.Height)
|
||||
labelTL := labelPosition.GetPointOnBox(edge.Dst.Box, label.PADDING, labelWidth, labelHeight)
|
||||
|
||||
endingSegment := geo.Segment{Start: points[endIndex-1], End: points[endIndex]}
|
||||
labelBox := geo.NewBox(labelTL, labelWidth, labelHeight)
|
||||
// add left/right padding to box
|
||||
labelBox.TopLeft.X -= label.PADDING
|
||||
labelBox.Width += 2 * label.PADDING
|
||||
if intersections := labelBox.Intersections(endingSegment); len(intersections) > 0 {
|
||||
overlapsOutsideLabel = true
|
||||
// move ending segment to label intersection point
|
||||
points[endIndex] = intersections[0]
|
||||
endingSegment.End = intersections[0]
|
||||
// if the segment becomes too short, just merge it with the previous segment
|
||||
if endIndex-1 > 0 && endingSegment.Length() < MIN_SEGMENT_LEN {
|
||||
points[endIndex-1] = points[endIndex]
|
||||
endIndex--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !overlapsOutsideLabel {
|
||||
points[endIndex] = shape.TraceToShapeBorder(dstShape, points[endIndex], points[endIndex-1])
|
||||
}
|
||||
return startIndex, endIndex
|
||||
}
|
||||
|
|
|
|||
142
d2ir/compile.go
|
|
@ -1,6 +1,7 @@
|
|||
package d2ir
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"strings"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
|
|
@ -9,18 +10,46 @@ import (
|
|||
)
|
||||
|
||||
type compiler struct {
|
||||
err d2parser.ParseError
|
||||
err *d2parser.ParseError
|
||||
|
||||
fs fs.FS
|
||||
// importStack is used to detect cyclic imports.
|
||||
importStack []string
|
||||
// importCache enables reuse of files imported multiple times.
|
||||
importCache map[string]*Map
|
||||
utf16 bool
|
||||
}
|
||||
|
||||
type CompileOptions struct {
|
||||
UTF16 bool
|
||||
// Pass nil to disable imports.
|
||||
FS fs.FS
|
||||
}
|
||||
|
||||
func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
|
||||
c.err.Errors = append(c.err.Errors, d2parser.Errorf(n, f, v...).(d2ast.Error))
|
||||
}
|
||||
|
||||
func Compile(ast *d2ast.Map) (*Map, error) {
|
||||
c := &compiler{}
|
||||
func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, error) {
|
||||
if opts == nil {
|
||||
opts = &CompileOptions{}
|
||||
}
|
||||
c := &compiler{
|
||||
err: &d2parser.ParseError{},
|
||||
fs: opts.FS,
|
||||
|
||||
importCache: make(map[string]*Map),
|
||||
utf16: opts.UTF16,
|
||||
}
|
||||
m := &Map{}
|
||||
m.initRoot()
|
||||
m.parent.(*Field).References[0].Context.Scope = ast
|
||||
|
||||
c.pushImportStack(&d2ast.Import{
|
||||
Path: []*d2ast.StringBox{d2ast.RawStringBox(ast.GetRange().Path, true)},
|
||||
})
|
||||
defer c.popImportStack()
|
||||
|
||||
c.compileMap(m, ast)
|
||||
c.compileClasses(m)
|
||||
if !c.err.Empty() {
|
||||
|
|
@ -85,6 +114,25 @@ func (c *compiler) compileMap(dst *Map, ast *d2ast.Map) {
|
|||
Scope: ast,
|
||||
ScopeMap: dst,
|
||||
})
|
||||
case n.Import != nil:
|
||||
impn, ok := c._import(n.Import)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if impn.Map() == nil {
|
||||
c.errorf(n.Import, "cannot spread import non map into map")
|
||||
continue
|
||||
}
|
||||
OverlayMap(dst, impn.Map())
|
||||
|
||||
if impnf, ok := impn.(*Field); ok {
|
||||
if impnf.Primary_ != nil {
|
||||
dstf := ParentField(dst)
|
||||
if dstf != nil {
|
||||
dstf.Primary_ = impnf.Primary_
|
||||
}
|
||||
}
|
||||
}
|
||||
case n.Substitution != nil:
|
||||
panic("TODO")
|
||||
}
|
||||
|
|
@ -145,6 +193,46 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext)
|
|||
case BoardScenario, BoardStep:
|
||||
c.compileClasses(f.Map())
|
||||
}
|
||||
} else if refctx.Key.Value.Import != nil {
|
||||
n, ok := c._import(refctx.Key.Value.Import)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
switch n := n.(type) {
|
||||
case *Field:
|
||||
if n.Primary_ != nil {
|
||||
f.Primary_ = n.Primary_.Copy(f).(*Scalar)
|
||||
}
|
||||
if n.Composite != nil {
|
||||
f.Composite = n.Composite.Copy(f).(Composite)
|
||||
}
|
||||
case *Map:
|
||||
f.Composite = &Map{
|
||||
parent: f,
|
||||
}
|
||||
switch NodeBoardKind(f) {
|
||||
case BoardScenario:
|
||||
c.overlay(ParentBoard(f).Map(), f)
|
||||
case BoardStep:
|
||||
stepsMap := ParentMap(f)
|
||||
for i := range stepsMap.Fields {
|
||||
if stepsMap.Fields[i] == f {
|
||||
if i == 0 {
|
||||
c.overlay(ParentBoard(f).Map(), f)
|
||||
} else {
|
||||
c.overlay(stepsMap.Fields[i-1].Map(), f)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
OverlayMap(f.Map(), n)
|
||||
c.updateLinks(f.Map())
|
||||
switch NodeBoardKind(f) {
|
||||
case BoardScenario, BoardStep:
|
||||
c.compileClasses(f.Map())
|
||||
}
|
||||
}
|
||||
} else if refctx.Key.Value.ScalarBox().Unbox() != nil {
|
||||
// If the link is a board, we need to transform it into an absolute path.
|
||||
if f.Name == "link" {
|
||||
|
|
@ -157,6 +245,24 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext)
|
|||
}
|
||||
}
|
||||
|
||||
func (c *compiler) updateLinks(m *Map) {
|
||||
for _, f := range m.Fields {
|
||||
if f.Name == "link" {
|
||||
bida := BoardIDA(f)
|
||||
aida := IDA(f)
|
||||
if len(bida) != len(aida) {
|
||||
prependIDA := aida[:len(aida)-len(bida)]
|
||||
kp := d2ast.MakeKeyPath(prependIDA)
|
||||
s := d2format.Format(kp) + strings.TrimPrefix(f.Primary_.Value.ScalarString(), "root")
|
||||
f.Primary_.Value = d2ast.MakeValueBox(d2ast.FlatUnquotedString(s)).ScalarBox().Unbox()
|
||||
}
|
||||
}
|
||||
if f.Map() != nil {
|
||||
c.updateLinks(f.Map())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileLink(refctx *RefContext) {
|
||||
val := refctx.Key.Value.ScalarBox().Unbox().ScalarString()
|
||||
link, err := d2parser.ParseKey(val)
|
||||
|
|
@ -216,7 +322,7 @@ func (c *compiler) compileLink(refctx *RefContext) {
|
|||
// Create the absolute path by appending scope path with value specified
|
||||
scopeIDA = append(scopeIDA, linkIDA...)
|
||||
kp := d2ast.MakeKeyPath(scopeIDA)
|
||||
refctx.Key.Value = d2ast.MakeValueBox(d2ast.RawString(d2format.Format(kp), true))
|
||||
refctx.Key.Value = d2ast.MakeValueBox(d2ast.FlatUnquotedString(d2format.Format(kp)))
|
||||
}
|
||||
|
||||
func (c *compiler) compileEdges(refctx *RefContext) {
|
||||
|
|
@ -330,6 +436,34 @@ func (c *compiler) compileArray(dst *Array, a *d2ast.Array) {
|
|||
parent: dst,
|
||||
Value: v,
|
||||
}
|
||||
case *d2ast.Import:
|
||||
n, ok := c._import(v)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch n := n.(type) {
|
||||
case *Field:
|
||||
if v.Spread {
|
||||
a, ok := n.Composite.(*Array)
|
||||
if !ok {
|
||||
c.errorf(v, "can only spread import array into array")
|
||||
continue
|
||||
}
|
||||
dst.Values = append(dst.Values, a.Values...)
|
||||
continue
|
||||
}
|
||||
if n.Composite != nil {
|
||||
irv = n.Composite
|
||||
} else {
|
||||
irv = n.Primary_
|
||||
}
|
||||
case *Map:
|
||||
if v.Spread {
|
||||
c.errorf(v, "can only spread import array into array")
|
||||
continue
|
||||
}
|
||||
irv = n
|
||||
}
|
||||
case *d2ast.Substitution:
|
||||
// panic("TODO")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"oss.terrastruct.com/util-go/assert"
|
||||
"oss.terrastruct.com/util-go/diff"
|
||||
"oss.terrastruct.com/util-go/mapfs"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
"oss.terrastruct.com/d2/d2ir"
|
||||
|
|
@ -24,6 +25,7 @@ func TestCompile(t *testing.T) {
|
|||
t.Run("layers", testCompileLayers)
|
||||
t.Run("scenarios", testCompileScenarios)
|
||||
t.Run("steps", testCompileSteps)
|
||||
t.Run("imports", testCompileImports)
|
||||
}
|
||||
|
||||
type testCase struct {
|
||||
|
|
@ -45,10 +47,26 @@ func compile(t testing.TB, text string) (*d2ir.Map, error) {
|
|||
t.Helper()
|
||||
|
||||
d2Path := fmt.Sprintf("%v.d2", t.Name())
|
||||
ast, err := d2parser.Parse(d2Path, strings.NewReader(text), nil)
|
||||
assert.Success(t, err)
|
||||
return compileFS(t, d2Path, map[string]string{d2Path: text})
|
||||
}
|
||||
|
||||
m, err := d2ir.Compile(ast)
|
||||
func compileFS(t testing.TB, path string, mfs map[string]string) (*d2ir.Map, error) {
|
||||
t.Helper()
|
||||
|
||||
ast, err := d2parser.Parse(path, strings.NewReader(mfs[path]), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs, err := mapfs.New(mfs)
|
||||
assert.Success(t, err)
|
||||
t.Cleanup(func() {
|
||||
err = fs.Close()
|
||||
assert.Success(t, err)
|
||||
})
|
||||
m, err := d2ir.Compile(ast, &d2ir.CompileOptions{
|
||||
FS: fs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
36
d2ir/d2ir.go
|
|
@ -25,7 +25,7 @@ type Node interface {
|
|||
Map() *Map
|
||||
Equal(n2 Node) bool
|
||||
|
||||
ast() d2ast.Node
|
||||
AST() d2ast.Node
|
||||
fmt.Stringer
|
||||
|
||||
LastRef() Reference
|
||||
|
|
@ -100,11 +100,11 @@ func (n *Map) value() {}
|
|||
func (n *Array) composite() {}
|
||||
func (n *Map) composite() {}
|
||||
|
||||
func (n *Scalar) String() string { return d2format.Format(n.ast()) }
|
||||
func (n *Field) String() string { return d2format.Format(n.ast()) }
|
||||
func (n *Edge) String() string { return d2format.Format(n.ast()) }
|
||||
func (n *Array) String() string { return d2format.Format(n.ast()) }
|
||||
func (n *Map) String() string { return d2format.Format(n.ast()) }
|
||||
func (n *Scalar) String() string { return d2format.Format(n.AST()) }
|
||||
func (n *Field) String() string { return d2format.Format(n.AST()) }
|
||||
func (n *Edge) String() string { return d2format.Format(n.AST()) }
|
||||
func (n *Array) String() string { return d2format.Format(n.AST()) }
|
||||
func (n *Map) String() string { return d2format.Format(n.AST()) }
|
||||
|
||||
func (n *Scalar) LastRef() Reference { return parentRef(n) }
|
||||
func (n *Map) LastRef() Reference { return parentRef(n) }
|
||||
|
|
@ -855,11 +855,11 @@ func (m *Map) CreateEdge(eid *EdgeID, refctx *RefContext) (*Edge, error) {
|
|||
return e, nil
|
||||
}
|
||||
|
||||
func (s *Scalar) ast() d2ast.Node {
|
||||
func (s *Scalar) AST() d2ast.Node {
|
||||
return s.Value
|
||||
}
|
||||
|
||||
func (f *Field) ast() d2ast.Node {
|
||||
func (f *Field) AST() d2ast.Node {
|
||||
k := &d2ast.Key{
|
||||
Key: &d2ast.KeyPath{
|
||||
Path: []*d2ast.StringBox{
|
||||
|
|
@ -869,16 +869,16 @@ func (f *Field) ast() d2ast.Node {
|
|||
}
|
||||
|
||||
if f.Primary_ != nil {
|
||||
k.Primary = d2ast.MakeValueBox(f.Primary_.ast().(d2ast.Value)).ScalarBox()
|
||||
k.Primary = d2ast.MakeValueBox(f.Primary_.AST().(d2ast.Value)).ScalarBox()
|
||||
}
|
||||
if f.Composite != nil {
|
||||
k.Value = d2ast.MakeValueBox(f.Composite.ast().(d2ast.Value))
|
||||
k.Value = d2ast.MakeValueBox(f.Composite.AST().(d2ast.Value))
|
||||
}
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
func (e *Edge) ast() d2ast.Node {
|
||||
func (e *Edge) AST() d2ast.Node {
|
||||
astEdge := &d2ast.Edge{}
|
||||
|
||||
astEdge.Src = d2ast.MakeKeyPath(e.ID.SrcPath)
|
||||
|
|
@ -895,27 +895,27 @@ func (e *Edge) ast() d2ast.Node {
|
|||
}
|
||||
|
||||
if e.Primary_ != nil {
|
||||
k.Primary = d2ast.MakeValueBox(e.Primary_.ast().(d2ast.Value)).ScalarBox()
|
||||
k.Primary = d2ast.MakeValueBox(e.Primary_.AST().(d2ast.Value)).ScalarBox()
|
||||
}
|
||||
if e.Map_ != nil {
|
||||
k.Value = d2ast.MakeValueBox(e.Map_.ast().(*d2ast.Map))
|
||||
k.Value = d2ast.MakeValueBox(e.Map_.AST().(*d2ast.Map))
|
||||
}
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
func (a *Array) ast() d2ast.Node {
|
||||
func (a *Array) AST() d2ast.Node {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
astArray := &d2ast.Array{}
|
||||
for _, av := range a.Values {
|
||||
astArray.Nodes = append(astArray.Nodes, d2ast.MakeArrayNodeBox(av.ast().(d2ast.ArrayNode)))
|
||||
astArray.Nodes = append(astArray.Nodes, d2ast.MakeArrayNodeBox(av.AST().(d2ast.ArrayNode)))
|
||||
}
|
||||
return astArray
|
||||
}
|
||||
|
||||
func (m *Map) ast() d2ast.Node {
|
||||
func (m *Map) AST() d2ast.Node {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -926,10 +926,10 @@ func (m *Map) ast() d2ast.Node {
|
|||
astMap.Range = d2ast.MakeRange(",1:0:0-2:0:0")
|
||||
}
|
||||
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)))
|
||||
}
|
||||
for _, e := range m.Edges {
|
||||
astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(e.ast().(d2ast.MapNode)))
|
||||
astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(e.AST().(d2ast.MapNode)))
|
||||
}
|
||||
return astMap
|
||||
}
|
||||
|
|
|
|||
145
d2ir/import.go
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
package d2ir
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
"oss.terrastruct.com/d2/d2parser"
|
||||
)
|
||||
|
||||
func (c *compiler) pushImportStack(imp *d2ast.Import) (string, bool) {
|
||||
impPath := imp.PathWithPre()
|
||||
if impPath == "" && imp.Range.Path != "" {
|
||||
c.errorf(imp, "imports must specify a path to import")
|
||||
return "", false
|
||||
}
|
||||
if len(c.importStack) > 0 {
|
||||
if path.IsAbs(impPath) {
|
||||
c.errorf(imp, "import paths must be relative")
|
||||
return "", false
|
||||
}
|
||||
|
||||
if path.Ext(impPath) != ".d2" {
|
||||
impPath += ".d2"
|
||||
}
|
||||
|
||||
// Imports are always relative to the importing file.
|
||||
impPath = path.Join(path.Dir(c.importStack[len(c.importStack)-1]), impPath)
|
||||
}
|
||||
|
||||
for i, p := range c.importStack {
|
||||
if impPath == p {
|
||||
c.errorf(imp, "detected cyclic import chain: %s", formatCyclicChain(c.importStack[i:]))
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
c.importStack = append(c.importStack, impPath)
|
||||
return impPath, true
|
||||
}
|
||||
|
||||
func (c *compiler) popImportStack() {
|
||||
c.importStack = c.importStack[:len(c.importStack)-1]
|
||||
}
|
||||
|
||||
func formatCyclicChain(cyclicChain []string) string {
|
||||
var b strings.Builder
|
||||
for _, p := range cyclicChain {
|
||||
b.WriteString(p)
|
||||
b.WriteString(" -> ")
|
||||
}
|
||||
b.WriteString(cyclicChain[0])
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Returns either *Map or *Field.
|
||||
func (c *compiler) _import(imp *d2ast.Import) (Node, bool) {
|
||||
ir, ok := c.__import(imp)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
nilScopeMap(ir)
|
||||
if len(imp.IDA()) > 0 {
|
||||
f := ir.GetField(imp.IDA()...)
|
||||
if f == nil {
|
||||
c.errorf(imp, "import key %q doesn't exist inside import", imp.IDA())
|
||||
return nil, false
|
||||
}
|
||||
return f, true
|
||||
}
|
||||
return ir, true
|
||||
}
|
||||
|
||||
func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) {
|
||||
impPath, ok := c.pushImportStack(imp)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
defer c.popImportStack()
|
||||
|
||||
ir, ok := c.importCache[impPath]
|
||||
if ok {
|
||||
return ir, true
|
||||
}
|
||||
|
||||
var f fs.File
|
||||
var err error
|
||||
if c.fs == nil {
|
||||
f, err = os.Open(impPath)
|
||||
} else {
|
||||
f, err = c.fs.Open(impPath)
|
||||
}
|
||||
if err != nil {
|
||||
c.errorf(imp, "failed to import %q: %v", impPath, err)
|
||||
return nil, false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
ast, err := d2parser.Parse(impPath, bufio.NewReader(f), &d2parser.ParseOptions{
|
||||
UTF16: c.utf16,
|
||||
ParseError: c.err,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
ir = &Map{}
|
||||
ir.initRoot()
|
||||
ir.parent.(*Field).References[0].Context.Scope = ast
|
||||
|
||||
c.compileMap(ir, ast)
|
||||
|
||||
c.importCache[impPath] = ir
|
||||
|
||||
return ir, true
|
||||
}
|
||||
|
||||
func nilScopeMap(n Node) {
|
||||
switch n := n.(type) {
|
||||
case *Map:
|
||||
for _, f := range n.Fields {
|
||||
nilScopeMap(f)
|
||||
}
|
||||
for _, e := range n.Edges {
|
||||
nilScopeMap(e)
|
||||
}
|
||||
case *Edge:
|
||||
for _, r := range n.References {
|
||||
r.Context.ScopeMap = nil
|
||||
}
|
||||
if n.Map() != nil {
|
||||
nilScopeMap(n.Map())
|
||||
}
|
||||
case *Field:
|
||||
for _, r := range n.References {
|
||||
r.Context.ScopeMap = nil
|
||||
}
|
||||
if n.Map() != nil {
|
||||
nilScopeMap(n.Map())
|
||||
}
|
||||
}
|
||||
}
|
||||
214
d2ir/import_test.go
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
package d2ir_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"oss.terrastruct.com/util-go/assert"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ir"
|
||||
)
|
||||
|
||||
func testCompileImports(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tca := []testCase{
|
||||
{
|
||||
name: "value",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "x: @x.d2",
|
||||
"x.d2": `shape: circle
|
||||
label: meow`,
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 3, 0, nil, "")
|
||||
assertQuery(t, m, 2, 0, nil, "x")
|
||||
assertQuery(t, m, 0, 0, "circle", "x.shape")
|
||||
assertQuery(t, m, 0, 0, "meow", "x.label")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested/map",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "x: @x.y",
|
||||
"x.d2": `y: {
|
||||
shape: circle
|
||||
label: meow
|
||||
}`,
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 3, 0, nil, "")
|
||||
assertQuery(t, m, 2, 0, nil, "x")
|
||||
assertQuery(t, m, 0, 0, "circle", "x.shape")
|
||||
assertQuery(t, m, 0, 0, "meow", "x.label")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested/array",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "x: @x.y",
|
||||
"x.d2": `y: [1, 2]`,
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 1, 0, nil, "")
|
||||
x := assertQuery(t, m, 0, 0, nil, "x")
|
||||
xf, ok := x.(*d2ir.Field)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, `[1, 2]`, xf.Composite.String())
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested/scalar",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "x: @x.y",
|
||||
"x.d2": `y: meow`,
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 1, 0, nil, "")
|
||||
assertQuery(t, m, 0, 0, "meow", "x")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "boards",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": `x.link: layers.x; layers: { x: @x }`,
|
||||
"x.d2": `y.link: layers.y; layers: { y: @y }`,
|
||||
"y.d2": `meow`,
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 0, 0, "root.layers.x", "x.link")
|
||||
assertQuery(t, m, 0, 0, "root.layers.x.layers.y", "layers.x.y.link")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "steps-inheritence",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": `z; steps: { 1: @x; 2: @y }; scenarios: { x: @x; y: @y }`,
|
||||
"x.d2": `a`,
|
||||
"y.d2": `b`,
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 2, 0, nil, "scenarios.x")
|
||||
assertQuery(t, m, 2, 0, nil, "scenarios.y")
|
||||
assertQuery(t, m, 2, 0, nil, "steps.1")
|
||||
assertQuery(t, m, 3, 0, nil, "steps.2")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "spread",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@x.d2",
|
||||
"x.d2": "x: wowa",
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 1, 0, nil, "")
|
||||
assertQuery(t, m, 0, 0, "wowa", "x")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested/spread",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@x.y",
|
||||
"x.d2": "y: { jon; jan }",
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 2, 0, nil, "")
|
||||
assertQuery(t, m, 0, 0, nil, "jan")
|
||||
assertQuery(t, m, 0, 0, nil, "jon")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested/spread_primary",
|
||||
run: func(t testing.TB) {
|
||||
m, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "q: { ...@x.y }",
|
||||
"x.d2": "y: meow { jon; jan }",
|
||||
})
|
||||
assert.Success(t, err)
|
||||
assertQuery(t, m, 3, 0, nil, "")
|
||||
assertQuery(t, m, 2, 0, "meow", "q")
|
||||
assertQuery(t, m, 0, 0, nil, "q.jan")
|
||||
assertQuery(t, m, 0, 0, nil, "q.jon")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runa(t, tca)
|
||||
|
||||
t.Run("errors", func(t *testing.T) {
|
||||
tca := []testCase{
|
||||
{
|
||||
name: "not_exist",
|
||||
run: func(t testing.TB) {
|
||||
_, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@x.d2",
|
||||
})
|
||||
assert.ErrorString(t, err, `index.d2:1:1: failed to import "x.d2": open x.d2: no such file or directory`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "escape",
|
||||
run: func(t testing.TB) {
|
||||
_, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@'./../x.d2'",
|
||||
})
|
||||
assert.ErrorString(t, err, `index.d2:1:1: failed to import "../x.d2": stat ../x.d2: invalid argument`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "absolute",
|
||||
run: func(t testing.TB) {
|
||||
_, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@/x.d2",
|
||||
})
|
||||
assert.ErrorString(t, err, `index.d2:1:1: import paths must be relative`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "parse",
|
||||
run: func(t testing.TB) {
|
||||
_, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@x.d2",
|
||||
"x.d2": "x<><><<>q",
|
||||
})
|
||||
assert.ErrorString(t, err, `x.d2:1:1: connection missing destination
|
||||
x.d2:1:4: connection missing source
|
||||
x.d2:1:4: connection missing destination
|
||||
x.d2:1:6: connection missing source
|
||||
x.d2:1:6: connection missing destination
|
||||
x.d2:1:7: connection missing source`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cyclic",
|
||||
run: func(t testing.TB) {
|
||||
_, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@x",
|
||||
"x.d2": "...@y",
|
||||
"y.d2": "...@q",
|
||||
"q.d2": "...@x",
|
||||
})
|
||||
assert.ErrorString(t, err, `q.d2:1:1: detected cyclic import chain: x.d2 -> y.d2 -> q.d2 -> x.d2`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "spread_non_map",
|
||||
run: func(t testing.TB) {
|
||||
_, err := compileFS(t, "index.d2", map[string]string{
|
||||
"index.d2": "...@x.y",
|
||||
"x.d2": "y: meow",
|
||||
})
|
||||
assert.ErrorString(t, err, `index.d2:1:1: cannot spread import non map into map`)
|
||||
},
|
||||
},
|
||||
}
|
||||
runa(t, tca)
|
||||
})
|
||||
}
|
||||
|
|
@ -21,7 +21,6 @@ import (
|
|||
"oss.terrastruct.com/d2/lib/geo"
|
||||
"oss.terrastruct.com/d2/lib/label"
|
||||
"oss.terrastruct.com/d2/lib/log"
|
||||
"oss.terrastruct.com/d2/lib/shape"
|
||||
)
|
||||
|
||||
//go:embed setup.js
|
||||
|
|
@ -31,9 +30,8 @@ var setupJS string
|
|||
var dagreJS string
|
||||
|
||||
const (
|
||||
MIN_SEGMENT_LEN = 10
|
||||
MIN_RANK_SEP = 60
|
||||
EDGE_LABEL_GAP = 20
|
||||
MIN_RANK_SEP = 60
|
||||
EDGE_LABEL_GAP = 20
|
||||
)
|
||||
|
||||
type ConfigurableOpts struct {
|
||||
|
|
@ -384,7 +382,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
|
|||
if isHorizontal && e.Src.Parent != g.Root && e.Dst.Parent != g.Root {
|
||||
moveWholeEdge = true
|
||||
} else {
|
||||
e.Route[0].Y += stepSize
|
||||
e.ShiftStart(stepSize, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +391,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
|
|||
if isHorizontal && e.Dst.Parent != g.Root && e.Src.Parent != g.Root {
|
||||
moveWholeEdge = true
|
||||
} else {
|
||||
e.Route[len(e.Route)-1].Y += stepSize
|
||||
e.ShiftEnd(stepSize, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -433,7 +431,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
|
|||
// to fix this, we try extending the previous segment into the shape instead of having a very short segment
|
||||
if !start.Equals(points[0]) && startIndex+2 < len(points) {
|
||||
newStartingSegment := *geo.NewSegment(start, points[startIndex+1])
|
||||
if newStartingSegment.Length() < MIN_SEGMENT_LEN {
|
||||
if newStartingSegment.Length() < d2graph.MIN_SEGMENT_LEN {
|
||||
// we don't want a very short segment right next to the source because it will mess up the arrowhead
|
||||
// instead we want to extend the next segment into the shape border if possible
|
||||
nextStart := points[startIndex+1]
|
||||
|
|
@ -442,30 +440,32 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
|
|||
// Note: in other direction to extend towards source
|
||||
nextSegment := *geo.NewSegment(nextStart, nextEnd)
|
||||
v := nextSegment.ToVector()
|
||||
extendedStart := nextEnd.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint()
|
||||
extendedStart := nextEnd.ToVector().Add(v.AddLength(d2graph.MIN_SEGMENT_LEN)).ToPoint()
|
||||
extended := *geo.NewSegment(nextEnd, extendedStart)
|
||||
|
||||
if intersections := edge.Src.Box.Intersections(extended); len(intersections) > 0 {
|
||||
start = intersections[0]
|
||||
startIndex += 1
|
||||
startIndex++
|
||||
points[startIndex] = intersections[0]
|
||||
start = points[startIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
if !end.Equals(points[len(points)-1]) && endIndex-2 >= 0 {
|
||||
newEndingSegment := *geo.NewSegment(end, points[endIndex-1])
|
||||
if newEndingSegment.Length() < MIN_SEGMENT_LEN {
|
||||
if newEndingSegment.Length() < d2graph.MIN_SEGMENT_LEN {
|
||||
// extend the prev segment into the shape border if possible
|
||||
prevStart := points[endIndex-2]
|
||||
prevEnd := points[endIndex-1]
|
||||
|
||||
prevSegment := *geo.NewSegment(prevStart, prevEnd)
|
||||
v := prevSegment.ToVector()
|
||||
extendedEnd := prevStart.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint()
|
||||
extendedEnd := prevStart.ToVector().Add(v.AddLength(d2graph.MIN_SEGMENT_LEN)).ToPoint()
|
||||
extended := *geo.NewSegment(prevStart, extendedEnd)
|
||||
|
||||
if intersections := edge.Dst.Box.Intersections(extended); len(intersections) > 0 {
|
||||
end = intersections[0]
|
||||
endIndex -= 1
|
||||
endIndex--
|
||||
points[endIndex] = intersections[0]
|
||||
end = points[endIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -489,41 +489,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
|
|||
}
|
||||
}
|
||||
|
||||
srcShape := edge.Src.ToShape()
|
||||
dstShape := edge.Dst.ToShape()
|
||||
|
||||
// trace the edge to the specific shape's border
|
||||
points[startIndex] = shape.TraceToShapeBorder(srcShape, start, points[startIndex+1])
|
||||
|
||||
// if an edge to a container runs into its label, stop the edge at the label instead
|
||||
overlapsContainerLabel := false
|
||||
if edge.Dst.IsContainer() && edge.Dst.Label.Value != "" && !dstShape.Is(shape.TEXT_TYPE) {
|
||||
// assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
|
||||
labelWidth := float64(edge.Dst.LabelDimensions.Width)
|
||||
labelHeight := float64(edge.Dst.LabelDimensions.Height)
|
||||
labelTL := label.Position(*edge.Dst.LabelPosition).
|
||||
GetPointOnBox(edge.Dst.Box, label.PADDING, labelWidth, labelHeight)
|
||||
|
||||
endingSegment := geo.Segment{Start: points[endIndex-1], End: points[endIndex]}
|
||||
labelBox := geo.NewBox(labelTL, labelWidth, labelHeight)
|
||||
// add left/right padding to box
|
||||
labelBox.TopLeft.X -= label.PADDING
|
||||
labelBox.Width += 2 * label.PADDING
|
||||
if intersections := labelBox.Intersections(endingSegment); len(intersections) > 0 {
|
||||
overlapsContainerLabel = true
|
||||
// move ending segment to label intersection point
|
||||
points[endIndex] = intersections[0]
|
||||
endingSegment.End = intersections[0]
|
||||
// if the segment becomes too short, just merge it with the previous segment
|
||||
if endIndex-1 > 0 && endingSegment.Length() < MIN_SEGMENT_LEN {
|
||||
points[endIndex-1] = points[endIndex]
|
||||
endIndex--
|
||||
}
|
||||
}
|
||||
}
|
||||
if !overlapsContainerLabel {
|
||||
points[endIndex] = shape.TraceToShapeBorder(dstShape, end, points[endIndex-1])
|
||||
}
|
||||
startIndex, endIndex = edge.TraceToShape(points, startIndex, endIndex)
|
||||
points = points[startIndex : endIndex+1]
|
||||
|
||||
// build a curved path from the dagre route
|
||||
|
|
@ -578,22 +544,7 @@ func getEdgeEndpoints(g *d2graph.Graph, edge *d2graph.Edge) (*d2graph.Object, *d
|
|||
}
|
||||
dst := edge.Dst
|
||||
for len(dst.Children) > 0 && dst.Class == nil && dst.SQLTable == nil {
|
||||
dst = dst.ChildrenArray[0]
|
||||
|
||||
// We want to get the top node of destinations
|
||||
for _, child := range dst.ChildrenArray {
|
||||
isHead := true
|
||||
for _, e := range g.Edges {
|
||||
if inContainer(e.Src, child) != nil && inContainer(e.Dst, dst) != nil {
|
||||
isHead = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isHead {
|
||||
dst = child
|
||||
break
|
||||
}
|
||||
}
|
||||
dst = getLongestEdgeChainHead(g, dst)
|
||||
}
|
||||
if edge.SrcArrow && !edge.DstArrow {
|
||||
// for `b <- a`, edge.Edge is `a -> b` and we expect this routing result
|
||||
|
|
@ -641,8 +592,73 @@ func generateAddEdgeLine(fromID, toID, edgeID string, width, height int) string
|
|||
return fmt.Sprintf("g.setEdge({v:`%s`, w:`%s`, name:`%s`}, { width:%d, height:%d, labelpos: `c` });\n", escapeID(fromID), escapeID(toID), escapeID(edgeID), width, height)
|
||||
}
|
||||
|
||||
// getLongestEdgeChainHead finds the longest chain in a container and gets its head
|
||||
// If there are multiple chains of the same length, get the head closest to the center
|
||||
func getLongestEdgeChainHead(g *d2graph.Graph, container *d2graph.Object) *d2graph.Object {
|
||||
rank := make(map[*d2graph.Object]int)
|
||||
chainLength := make(map[*d2graph.Object]int)
|
||||
|
||||
for _, obj := range container.ChildrenArray {
|
||||
isHead := true
|
||||
for _, e := range g.Edges {
|
||||
if inContainer(e.Src, container) != nil && inContainer(e.Dst, obj) != nil {
|
||||
isHead = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isHead {
|
||||
continue
|
||||
}
|
||||
rank[obj] = 1
|
||||
chainLength[obj] = 1
|
||||
// BFS
|
||||
queue := []*d2graph.Object{obj}
|
||||
visited := make(map[*d2graph.Object]struct{})
|
||||
for len(queue) > 0 {
|
||||
curr := queue[0]
|
||||
queue = queue[1:]
|
||||
if _, ok := visited[curr]; ok {
|
||||
continue
|
||||
}
|
||||
visited[curr] = struct{}{}
|
||||
for _, e := range g.Edges {
|
||||
child := inContainer(e.Dst, container)
|
||||
if child == curr {
|
||||
continue
|
||||
}
|
||||
if child != nil && inContainer(e.Src, curr) != nil {
|
||||
if rank[curr]+1 > rank[child] {
|
||||
rank[child] = rank[curr] + 1
|
||||
chainLength[obj] = go2.Max(chainLength[obj], rank[child])
|
||||
}
|
||||
queue = append(queue, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
max := int(math.MinInt32)
|
||||
for _, obj := range container.ChildrenArray {
|
||||
if chainLength[obj] > max {
|
||||
max = chainLength[obj]
|
||||
}
|
||||
}
|
||||
|
||||
var heads []*d2graph.Object
|
||||
for i, obj := range container.ChildrenArray {
|
||||
if rank[obj] == 1 && chainLength[obj] == max {
|
||||
heads = append(heads, container.ChildrenArray[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(heads) > 0 {
|
||||
return heads[int(math.Floor(float64(len(heads))/2.0))]
|
||||
}
|
||||
return container.ChildrenArray[0]
|
||||
}
|
||||
|
||||
// getLongestEdgeChainTail gets the node at the end of the longest edge chain, because that will be the end of the container
|
||||
// and is what external connections should connect with
|
||||
// and is what external connections should connect with.
|
||||
// If there are multiple of same length, get the one closest to the middle
|
||||
func getLongestEdgeChainTail(g *d2graph.Graph, container *d2graph.Object) *d2graph.Object {
|
||||
rank := make(map[*d2graph.Object]int)
|
||||
|
||||
|
|
@ -681,14 +697,20 @@ func getLongestEdgeChainTail(g *d2graph.Graph, container *d2graph.Object) *d2gra
|
|||
}
|
||||
}
|
||||
max := int(math.MinInt32)
|
||||
var tail *d2graph.Object
|
||||
for _, obj := range container.ChildrenArray {
|
||||
if rank[obj] >= max {
|
||||
if rank[obj] > max {
|
||||
max = rank[obj]
|
||||
tail = obj
|
||||
}
|
||||
}
|
||||
return tail
|
||||
|
||||
var tails []*d2graph.Object
|
||||
for i, obj := range container.ChildrenArray {
|
||||
if rank[obj] == max {
|
||||
tails = append(tails, container.ChildrenArray[i])
|
||||
}
|
||||
}
|
||||
|
||||
return tails[int(math.Floor(float64(len(tails))/2.0))]
|
||||
}
|
||||
|
||||
func inContainer(obj, container *d2graph.Object) *d2graph.Object {
|
||||
|
|
|
|||
|
|
@ -501,12 +501,8 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
|
|||
}
|
||||
}
|
||||
|
||||
srcShape := edge.Src.ToShape()
|
||||
dstShape := edge.Dst.ToShape()
|
||||
|
||||
// trace the edge to the specific shape's border
|
||||
points[startIndex] = shape.TraceToShapeBorder(srcShape, points[startIndex], points[startIndex+1])
|
||||
points[endIndex] = shape.TraceToShapeBorder(dstShape, points[endIndex], points[endIndex-1])
|
||||
startIndex, endIndex = edge.TraceToShape(points, startIndex, endIndex)
|
||||
points = points[startIndex : endIndex+1]
|
||||
|
||||
if edge.Label.Value != "" {
|
||||
edge.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ func (gd *gridDiagram) getBestLayout(targetSize float64, columns bool) [][]*d2gr
|
|||
nCuts = gd.rows - 1
|
||||
}
|
||||
if nCuts == 0 {
|
||||
return genLayout(gd.objects, nil)
|
||||
return GenLayout(gd.objects, nil)
|
||||
}
|
||||
|
||||
var bestLayout [][]*d2graph.Object
|
||||
|
|
@ -692,7 +692,7 @@ func (gd *gridDiagram) getBestLayout(targetSize float64, columns bool) [][]*d2gr
|
|||
// . A │ B │ C D E └────────────┘
|
||||
// of these divisions, find the layout with rows closest to the targetSize
|
||||
tryDivision := func(division []int) bool {
|
||||
layout := genLayout(gd.objects, division)
|
||||
layout := GenLayout(gd.objects, division)
|
||||
dist := getDistToTarget(layout, targetSize, float64(gd.horizontalGap), float64(gd.verticalGap), columns)
|
||||
if dist < bestDist {
|
||||
bestLayout = layout
|
||||
|
|
@ -786,8 +786,10 @@ func (gd *gridDiagram) fastLayout(targetSize float64, nCuts int, columns bool) (
|
|||
size = o.Width
|
||||
}
|
||||
if rowSize == 0 {
|
||||
// if a single object meets the target size, end the row here
|
||||
if size > targetSize-debt {
|
||||
fastDivision = append(fastDivision, i-1)
|
||||
// cut row with just this object
|
||||
fastDivision = append(fastDivision, i)
|
||||
// we build up a debt of distance past the target size across rows
|
||||
newDebt := size - targetSize
|
||||
debt += newDebt
|
||||
|
|
@ -797,7 +799,11 @@ func (gd *gridDiagram) fastLayout(targetSize float64, nCuts int, columns bool) (
|
|||
continue
|
||||
}
|
||||
// debt is paid by decreasing threshold to start new row and ending below targetSize
|
||||
if rowSize+(gap+size)/2. > targetSize-debt {
|
||||
if rowSize+gap+(size)/2. > targetSize-debt {
|
||||
// start a new row before this object since it is mostly past the target size
|
||||
// . size
|
||||
// ├...row─┼gap┼───┼───┤
|
||||
// ├──targetSize──┤ (debt=0)
|
||||
fastDivision = append(fastDivision, i-1)
|
||||
newDebt := rowSize - targetSize
|
||||
debt += newDebt
|
||||
|
|
@ -807,7 +813,7 @@ func (gd *gridDiagram) fastLayout(targetSize float64, nCuts int, columns bool) (
|
|||
}
|
||||
}
|
||||
if len(fastDivision) == nCuts {
|
||||
layout = genLayout(gd.objects, fastDivision)
|
||||
layout = GenLayout(gd.objects, fastDivision)
|
||||
}
|
||||
|
||||
return layout
|
||||
|
|
@ -885,7 +891,9 @@ func iterDivisions(objects []*d2graph.Object, nCuts int, f iterDivision, check c
|
|||
}
|
||||
|
||||
// generate a grid of objects from the given cut indices
|
||||
func genLayout(objects []*d2graph.Object, cutIndices []int) [][]*d2graph.Object {
|
||||
// each cut index applies after the object at that index
|
||||
// e.g. [0 1 2 3 4 5 6 7] with cutIndices [0, 2, 6] => [[0], [1, 2], [3,4,5,6], [7]]
|
||||
func GenLayout(objects []*d2graph.Object, cutIndices []int) [][]*d2graph.Object {
|
||||
layout := make([][]*d2graph.Object, len(cutIndices)+1)
|
||||
objIndex := 0
|
||||
for i := 0; i <= len(cutIndices); i++ {
|
||||
|
|
@ -916,6 +924,13 @@ func getDistToTarget(layout [][]*d2graph.Object, targetSize float64, horizontalG
|
|||
rowSize += o.Width + horizontalGap
|
||||
}
|
||||
}
|
||||
if len(row) > 0 {
|
||||
if columns {
|
||||
rowSize -= verticalGap
|
||||
} else {
|
||||
rowSize -= horizontalGap
|
||||
}
|
||||
}
|
||||
totalDelta += math.Abs(rowSize - targetSize)
|
||||
}
|
||||
return totalDelta
|
||||
|
|
|
|||
72
d2layouts/d2grid/layout_test.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package d2grid_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"oss.terrastruct.com/d2/d2graph"
|
||||
"oss.terrastruct.com/d2/d2layouts/d2grid"
|
||||
)
|
||||
|
||||
func TestGenLayout(t *testing.T) {
|
||||
objects := []*d2graph.Object{
|
||||
{ID: "1"},
|
||||
{ID: "2"},
|
||||
{ID: "3"},
|
||||
{ID: "4"},
|
||||
{ID: "5"},
|
||||
{ID: "6"},
|
||||
{ID: "7"},
|
||||
{ID: "8"},
|
||||
}
|
||||
var cutIndices []int
|
||||
var layout [][]*d2graph.Object
|
||||
cutIndices = []int{0}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
fmt.Printf("layout %v\n", len(layout))
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 2 rows from 1 cut")
|
||||
assert.Equalf(t, 1, len(layout[0]), "expected first row to be 1 object")
|
||||
assert.Equalf(t, 7, len(layout[1]), "expected second row to be 7 objects")
|
||||
assert.Equalf(t, objects[0].ID, layout[0][0].ID, "expected first object to be 1")
|
||||
|
||||
cutIndices = []int{6}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 2 rows from 1 cut")
|
||||
assert.Equalf(t, 7, len(layout[0]), "expected first row to be 7 objects")
|
||||
assert.Equalf(t, 1, len(layout[1]), "expected second row to be 1 object")
|
||||
|
||||
cutIndices = []int{0, 6}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 3 rows from 2 cuts")
|
||||
assert.Equalf(t, 1, len(layout[0]), "expected first row to be 1 objects")
|
||||
assert.Equalf(t, 6, len(layout[1]), "expected second row to be 6 objects")
|
||||
assert.Equalf(t, 1, len(layout[2]), "expected second row to be 1 object")
|
||||
|
||||
cutIndices = []int{1, 5}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 3 rows from 2 cuts")
|
||||
assert.Equalf(t, 2, len(layout[0]), "expected first row to be 2 objects")
|
||||
assert.Equalf(t, 4, len(layout[1]), "expected second row to be 6 objects")
|
||||
assert.Equalf(t, 2, len(layout[2]), "expected second row to be 2 object")
|
||||
|
||||
cutIndices = []int{5}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 2 rows from 1 cut")
|
||||
assert.Equalf(t, 6, len(layout[0]), "expected first row to be 6 objects")
|
||||
assert.Equalf(t, 2, len(layout[1]), "expected second row to be 2 object")
|
||||
|
||||
cutIndices = []int{1}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 2 rows from 1 cut")
|
||||
assert.Equalf(t, 2, len(layout[0]), "expected first row to be 2 object")
|
||||
assert.Equalf(t, 6, len(layout[1]), "expected second row to be 6 objects")
|
||||
|
||||
cutIndices = []int{0, 1, 2, 3, 4, 5, 6}
|
||||
layout = d2grid.GenLayout(objects, cutIndices)
|
||||
assert.Equalf(t, len(cutIndices)+1, len(layout), "expected 3 rows from 2 cuts")
|
||||
for i := range layout {
|
||||
assert.Equalf(t, 1, len(layout[i]), "expected row %d to be 1 object", i)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package d2lib
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ import (
|
|||
|
||||
type CompileOptions struct {
|
||||
UTF16 bool
|
||||
FS fs.FS
|
||||
MeasuredTexts []*d2target.MText
|
||||
Ruler *textmeasure.Ruler
|
||||
Layout func(context.Context, *d2graph.Graph) error
|
||||
|
|
@ -31,6 +33,8 @@ type CompileOptions struct {
|
|||
// - pre-measured (web setting)
|
||||
// TODO maybe some will want to configure code font too, but that's much lower priority
|
||||
FontFamily *d2fonts.FontFamily
|
||||
|
||||
InputPath string
|
||||
}
|
||||
|
||||
func Compile(ctx context.Context, input string, opts *CompileOptions) (*d2target.Diagram, *d2graph.Graph, error) {
|
||||
|
|
@ -38,8 +42,9 @@ func Compile(ctx context.Context, input string, opts *CompileOptions) (*d2target
|
|||
opts = &CompileOptions{}
|
||||
}
|
||||
|
||||
g, err := d2compiler.Compile("", strings.NewReader(input), &d2compiler.CompileOptions{
|
||||
g, err := d2compiler.Compile(opts.InputPath, strings.NewReader(input), &d2compiler.CompileOptions{
|
||||
UTF16: opts.UTF16,
|
||||
FS: opts.FS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ func _set(g *d2graph.Graph, key string, tag, value *string) error {
|
|||
}
|
||||
}
|
||||
|
||||
ir, err := d2ir.Compile(g.AST)
|
||||
ir, err := d2ir.Compile(g.AST, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ import (
|
|||
)
|
||||
|
||||
type ParseOptions struct {
|
||||
UTF16 bool
|
||||
UTF16 bool
|
||||
ParseError *ParseError
|
||||
}
|
||||
|
||||
// Parse parses a .d2 Map in r.
|
||||
|
|
@ -42,6 +43,10 @@ func Parse(path string, r io.RuneReader, opts *ParseOptions) (*d2ast.Map, error)
|
|||
reader: r,
|
||||
|
||||
utf16: opts.UTF16,
|
||||
err: opts.ParseError,
|
||||
}
|
||||
if p.err == nil {
|
||||
p.err = &ParseError{}
|
||||
}
|
||||
|
||||
m := p.parseMap(true)
|
||||
|
|
@ -54,6 +59,7 @@ func Parse(path string, r io.RuneReader, opts *ParseOptions) (*d2ast.Map, error)
|
|||
func ParseKey(key string) (*d2ast.KeyPath, error) {
|
||||
p := &parser{
|
||||
reader: strings.NewReader(key),
|
||||
err: &ParseError{},
|
||||
}
|
||||
|
||||
k := p.parseKey()
|
||||
|
|
@ -69,6 +75,7 @@ func ParseKey(key string) (*d2ast.KeyPath, error) {
|
|||
func ParseMapKey(mapKey string) (*d2ast.Key, error) {
|
||||
p := &parser{
|
||||
reader: strings.NewReader(mapKey),
|
||||
err: &ParseError{},
|
||||
}
|
||||
|
||||
mk := p.parseMapKey()
|
||||
|
|
@ -84,6 +91,7 @@ func ParseMapKey(mapKey string) (*d2ast.Key, error) {
|
|||
func ParseValue(value string) (d2ast.Value, error) {
|
||||
p := &parser{
|
||||
reader: strings.NewReader(value),
|
||||
err: &ParseError{},
|
||||
}
|
||||
|
||||
v := p.parseValue()
|
||||
|
|
@ -117,18 +125,16 @@ type parser struct {
|
|||
lookaheadPos d2ast.Position
|
||||
|
||||
ioerr bool
|
||||
err ParseError
|
||||
err *ParseError
|
||||
|
||||
inEdgeGroup bool
|
||||
|
||||
depth int
|
||||
}
|
||||
|
||||
// TODO: remove ioerr, just sort (with Append) should be fine but filter non ast errors in API
|
||||
// TODO: rename to Error and make existing Error a private type errorWithRange
|
||||
type ParseError struct {
|
||||
IOError *d2ast.Error `json:"ioerr"`
|
||||
Errors []d2ast.Error `json:"errs"`
|
||||
Errors []d2ast.Error `json:"errs"`
|
||||
}
|
||||
|
||||
func Errorf(n d2ast.Node, f string, v ...interface{}) error {
|
||||
|
|
@ -140,17 +146,17 @@ func Errorf(n d2ast.Node, f string, v ...interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
func (pe ParseError) Empty() bool {
|
||||
return pe.IOError == nil && len(pe.Errors) == 0
|
||||
func (pe *ParseError) Empty() bool {
|
||||
if pe == nil {
|
||||
return true
|
||||
}
|
||||
return len(pe.Errors) == 0
|
||||
}
|
||||
|
||||
func (pe ParseError) Error() string {
|
||||
func (pe *ParseError) Error() string {
|
||||
var sb strings.Builder
|
||||
if pe.IOError != nil {
|
||||
sb.WriteString(pe.IOError.Error())
|
||||
}
|
||||
for i, err := range pe.Errors {
|
||||
if pe.IOError != nil || i > 0 {
|
||||
if i > 0 {
|
||||
sb.WriteByte('\n')
|
||||
}
|
||||
sb.WriteString(err.Error())
|
||||
|
|
@ -191,14 +197,14 @@ func (p *parser) _readRune() (r rune, eof bool) {
|
|||
if err != nil {
|
||||
p.ioerr = true
|
||||
if err != io.EOF {
|
||||
p.err.IOError = &d2ast.Error{
|
||||
p.err.Errors = append(p.err.Errors, d2ast.Error{
|
||||
Range: d2ast.Range{
|
||||
Path: p.path,
|
||||
Start: p.readerPos,
|
||||
End: p.readerPos,
|
||||
},
|
||||
Message: fmt.Sprintf("io error: %v", err),
|
||||
}
|
||||
})
|
||||
}
|
||||
p.rewind()
|
||||
return 0, true
|
||||
|
|
@ -355,7 +361,7 @@ func (p *parser) parseMap(isFileMap bool) *d2ast.Map {
|
|||
Start: p.pos,
|
||||
},
|
||||
}
|
||||
defer m.Range.End.From(&p.readerPos)
|
||||
defer m.Range.End.From(&p.pos)
|
||||
|
||||
if !isFileMap {
|
||||
m.Range.Start = m.Range.Start.Subtract('{', p.utf16)
|
||||
|
|
@ -448,17 +454,30 @@ func (p *parser) parseMapNode(r rune) d2ast.MapNodeBox {
|
|||
box.BlockComment = p.parseBlockComment()
|
||||
return box
|
||||
case '.':
|
||||
s, eof := p.peekn(3)
|
||||
s, eof := p.peekn(2)
|
||||
if eof {
|
||||
break
|
||||
}
|
||||
if s != "..$" {
|
||||
if s != ".." {
|
||||
p.rewind()
|
||||
break
|
||||
}
|
||||
p.commit()
|
||||
box.Substitution = p.parseSubstitution(true)
|
||||
return box
|
||||
r, eof := p.peek()
|
||||
if eof {
|
||||
break
|
||||
}
|
||||
if r == '$' {
|
||||
p.commit()
|
||||
box.Substitution = p.parseSubstitution(true)
|
||||
return box
|
||||
}
|
||||
if r == '@' {
|
||||
p.commit()
|
||||
box.Import = p.parseImport(true)
|
||||
return box
|
||||
}
|
||||
p.rewind()
|
||||
break
|
||||
}
|
||||
|
||||
p.replay(r)
|
||||
|
|
@ -614,7 +633,7 @@ func (p *parser) parseMapKey() (mk *d2ast.Key) {
|
|||
}
|
||||
}()
|
||||
|
||||
// Check for ampersand.
|
||||
// Check for ampersand/@.
|
||||
r, eof := p.peek()
|
||||
if eof {
|
||||
return mk
|
||||
|
|
@ -948,6 +967,9 @@ func (p *parser) parseKey() (k *d2ast.KeyPath) {
|
|||
if s == nil {
|
||||
return k
|
||||
}
|
||||
if sb.UnquotedString != nil && strings.HasPrefix(s.ScalarString(), "@") {
|
||||
p.errorf(s.GetRange().Start, s.GetRange().End, "%s is not a valid import, did you mean ...%[2]s?", s.ScalarString())
|
||||
}
|
||||
|
||||
if len(k.Path) == 0 {
|
||||
k.Range.Start = s.GetRange().Start
|
||||
|
|
@ -1024,6 +1046,14 @@ func (p *parser) parseUnquotedString(inKey bool) (s *d2ast.UnquotedString) {
|
|||
s.Value = append(s.Value, d2ast.InterpolationBox{String: &sv, StringRaw: &rawv})
|
||||
}()
|
||||
|
||||
_s, eof := p.peekn(4)
|
||||
p.rewind()
|
||||
if !eof {
|
||||
if _s == "...@" {
|
||||
p.errorf(p.pos, p.pos.AdvanceString("...@", p.utf16), "unquoted strings cannot begin with ...@ as that's import spread syntax")
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
r, eof := p.peek()
|
||||
if eof {
|
||||
|
|
@ -1502,17 +1532,30 @@ func (p *parser) parseArrayNode(r rune) d2ast.ArrayNodeBox {
|
|||
box.BlockComment = p.parseBlockComment()
|
||||
return box
|
||||
case '.':
|
||||
s, eof := p.peekn(3)
|
||||
s, eof := p.peekn(2)
|
||||
if eof {
|
||||
break
|
||||
}
|
||||
if s != "..$" {
|
||||
if s != ".." {
|
||||
p.rewind()
|
||||
break
|
||||
}
|
||||
p.commit()
|
||||
box.Substitution = p.parseSubstitution(true)
|
||||
return box
|
||||
r, eof := p.peek()
|
||||
if eof {
|
||||
break
|
||||
}
|
||||
if r == '$' {
|
||||
p.commit()
|
||||
box.Substitution = p.parseSubstitution(true)
|
||||
return box
|
||||
}
|
||||
if r == '@' {
|
||||
p.commit()
|
||||
box.Import = p.parseImport(true)
|
||||
return box
|
||||
}
|
||||
p.rewind()
|
||||
break
|
||||
}
|
||||
|
||||
p.replay(r)
|
||||
|
|
@ -1529,6 +1572,7 @@ func (p *parser) parseArrayNode(r rune) d2ast.ArrayNodeBox {
|
|||
box.BlockString = vbox.BlockString
|
||||
box.Array = vbox.Array
|
||||
box.Map = vbox.Map
|
||||
box.Import = vbox.Import
|
||||
return box
|
||||
}
|
||||
|
||||
|
|
@ -1549,6 +1593,9 @@ func (p *parser) parseValue() d2ast.ValueBox {
|
|||
case '{':
|
||||
box.Map = p.parseMap(false)
|
||||
return box
|
||||
case '@':
|
||||
box.Import = p.parseImport(false)
|
||||
return box
|
||||
}
|
||||
|
||||
p.replay(r)
|
||||
|
|
@ -1659,6 +1706,46 @@ func (p *parser) parseSubstitution(spread bool) *d2ast.Substitution {
|
|||
return subst
|
||||
}
|
||||
|
||||
func (p *parser) parseImport(spread bool) *d2ast.Import {
|
||||
imp := &d2ast.Import{
|
||||
Range: d2ast.Range{
|
||||
Path: p.path,
|
||||
Start: p.pos.SubtractString("$", p.utf16),
|
||||
},
|
||||
Spread: spread,
|
||||
}
|
||||
defer imp.Range.End.From(&p.pos)
|
||||
|
||||
if imp.Spread {
|
||||
imp.Range.Start = imp.Range.Start.SubtractString("...", p.utf16)
|
||||
}
|
||||
|
||||
var pre strings.Builder
|
||||
for {
|
||||
r, eof := p.peek()
|
||||
if eof {
|
||||
break
|
||||
}
|
||||
if r != '.' && r != '/' {
|
||||
p.rewind()
|
||||
break
|
||||
}
|
||||
pre.WriteRune(r)
|
||||
p.commit()
|
||||
}
|
||||
imp.Pre = pre.String()
|
||||
|
||||
k := p.parseKey()
|
||||
if k == nil {
|
||||
return imp
|
||||
}
|
||||
if k.Path[0].UnquotedString != nil && len(k.Path) > 1 && k.Path[1].UnquotedString != nil && k.Path[1].Unbox().ScalarString() == "d2" {
|
||||
k.Path = append(k.Path[:1], k.Path[2:]...)
|
||||
}
|
||||
imp.Path = k.Path
|
||||
return imp
|
||||
}
|
||||
|
||||
// func marshalKey(k *d2ast.Key) string {
|
||||
// var sb strings.Builder
|
||||
// for i, s := range k.Path {
|
||||
|
|
|
|||
|
|
@ -13,20 +13,19 @@ import (
|
|||
"oss.terrastruct.com/d2/d2parser"
|
||||
)
|
||||
|
||||
type testCase struct {
|
||||
name string
|
||||
text string
|
||||
assert func(t testing.TB, ast *d2ast.Map, err error)
|
||||
}
|
||||
|
||||
// TODO: next step for parser is writing as many tests and grouping them nicely
|
||||
// TODO: add assertions
|
||||
// to layout *all* expected behavior.
|
||||
func TestParse(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
text string
|
||||
assert func(t testing.TB, ast *d2ast.Map, err error)
|
||||
|
||||
// exp is in testdata/d2parser/TestParse/${name}.json
|
||||
}{
|
||||
|
||||
var testCases = []testCase{
|
||||
{
|
||||
name: "empty",
|
||||
text: ``,
|
||||
|
|
@ -394,7 +393,99 @@ c-
|
|||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run("import", testImport)
|
||||
|
||||
runa(t, testCases)
|
||||
}
|
||||
|
||||
func testImport(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tca := []testCase{
|
||||
{
|
||||
text: "x: @file",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.Equal(t, "file", ast.Nodes[0].MapKey.Value.Import.Path[0].Unbox().ScalarString())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "x: @file.d2",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.Equal(t, "file", ast.Nodes[0].MapKey.Value.Import.Path[0].Unbox().ScalarString())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "...@file.d2",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.True(t, ast.Nodes[0].Import.Spread)
|
||||
assert.Equal(t, "file", ast.Nodes[0].Import.Path[0].Unbox().ScalarString())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "x: [...@file.d2]",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
imp := ast.Nodes[0].MapKey.Value.Array.Nodes[0].Import
|
||||
assert.True(t, imp.Spread)
|
||||
assert.Equal(t, "file", imp.Path[0].Unbox().ScalarString())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "...@\"file\".d2",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.True(t, ast.Nodes[0].Import.Spread)
|
||||
assert.Equal(t, "file", ast.Nodes[0].Import.Path[0].Unbox().ScalarString())
|
||||
assert.Equal(t, "d2", ast.Nodes[0].Import.Path[1].Unbox().ScalarString())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "...@file.\"d2\"",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.True(t, ast.Nodes[0].Import.Spread)
|
||||
assert.Equal(t, "file", ast.Nodes[0].Import.Path[0].Unbox().ScalarString())
|
||||
assert.Equal(t, "d2", ast.Nodes[0].Import.Path[1].Unbox().ScalarString())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "...@../file",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.True(t, ast.Nodes[0].Import.Spread)
|
||||
assert.Equal(t, "../file", ast.Nodes[0].Import.PathWithPre())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "@file",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.ErrorString(t, err, "d2/testdata/d2parser/TestParse/import/#07.d2:1:1: @file is not a valid import, did you mean ...@file?")
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "...@./../.././file",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assert.True(t, ast.Nodes[0].Import.Spread)
|
||||
assert.Equal(t, "../../file", ast.Nodes[0].Import.PathWithPre())
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "meow: ...@file",
|
||||
assert: func(t testing.TB, ast *d2ast.Map, err error) {
|
||||
assert.ErrorString(t, err, "d2/testdata/d2parser/TestParse/import/#09.d2:1:7: unquoted strings cannot begin with ...@ as that's import spread syntax")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runa(t, tca)
|
||||
}
|
||||
|
||||
func runa(t *testing.T, tca []testCase) {
|
||||
for _, tc := range tca {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"oss.terrastruct.com/util-go/xmain"
|
||||
|
||||
"oss.terrastruct.com/d2/d2graph"
|
||||
timelib "oss.terrastruct.com/d2/lib/time"
|
||||
)
|
||||
|
||||
// execPlugin uses the binary at pathname with the plugin protocol to implement
|
||||
|
|
@ -147,7 +148,7 @@ func (p *execPlugin) Info(ctx context.Context) (_ *PluginInfo, err error) {
|
|||
}
|
||||
|
||||
func (p *execPlugin) Layout(ctx context.Context, g *d2graph.Graph) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
||||
ctx, cancel := timelib.WithTimeout(ctx, time.Minute*2)
|
||||
defer cancel()
|
||||
|
||||
graphBytes, err := d2graph.SerializeGraph(g)
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 63 KiB |
|
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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-3945613123" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-3945613123" 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-3945613123 .text-mono {
|
||||
font-family: "d2-3945613123-font-mono";
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-3945613123" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-3945613123" 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-3945613123 .text-mono {
|
||||
font-family: "d2-3945613123-font-mono";
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 152 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 398 284"><svg id="d2-svg" class="d2-124739280" width="398" height="284" viewBox="-101 -102 398 284"><rect x="-101.000000" y="-102.000000" width="398.000000" height="284.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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 398 284"><svg id="d2-svg" class="d2-124739280" width="398" height="284" viewBox="-101 -102 398 284"><rect x="-101.000000" y="-102.000000" width="398.000000" height="284.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-124739280 .text-bold {
|
||||
font-family: "d2-124739280-font-bold";
|
||||
}
|
||||
|
|
@ -136,5 +136,6 @@
|
|||
<rect x="129" y="-5" width="66" height="84" fill="white"></rect>
|
||||
<path d="M141,10L156,3L182,3L195,37L182,72L167,79L141,79L129,44L141,10L167,10L180,44L167,79M167,10L182,3M180,44L195,37M167,79L182,72" style="stroke-width:2;;stroke:#000;fill:none;opacity:1;"/></mask></defs><polygon x="129.000000" y="10.000000" mask="url(#border-mask-y)" points="141,10 167,10 180,44 167,79 141,79 129,44" stroke="none" class=" fill-N5" style="stroke-width:2;" /><polygon x="129.000000" y="10.000000" mask="url(#border-mask-y)" points="141,10 167,10 180,44 167,79 141,79 129,44" class="dots-overlay" style="stroke-width:2;" /><polygon mask="url(#border-mask-y)" points="156,3 182,3 195,37 182,72 167,79 180,44 167,10 141,10" class=" fill-N4" style="stroke-width:2;" /><path d="M141,10 L156,3 L182,3 L195,37 L182,72 L167,79 L141,79 L129,44 L141,10 L167,10 L180,44 L167,79 M167,10 L182,3 M180,44 L195,37 M167,79 L182,72" fill="none" class=" stroke-B1" style="stroke-width:2;" /></g><text x="154.500000" y="50.000000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g><mask id="d2-124739280" maskUnits="userSpaceOnUse" x="-101" y="-102" width="398" height="284">
|
||||
<rect x="-101" y="-102" width="398" height="284" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="37.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="150.000000" y="34.000000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
563
d2renderers/d2sketch/testdata/opacity/sketch.exp.svg
vendored
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 493 KiB After Width: | Height: | Size: 493 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 676 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 407"><svg id="d2-svg" class="d2-916646398" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 407"><svg id="d2-svg" class="d2-916646398" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
.d2-916646398 .color-AB4{color:#EDF0FD;}
|
||||
.d2-916646398 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="root.layers.x" xlink:href="root.layers.x"><g id="x"><g class="shape" ><rect x="0.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="42.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text><g transform="translate(69 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g></g></a><mask id="d2-916646398" maskUnits="userSpaceOnUse" x="-101" y="-118" width="304" height="285">
|
||||
<rect x="-101" y="-118" width="304" height="285" fill="white"></rect>
|
||||
|
||||
<rect x="38.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask><line x1="-41.000000" x2="143.000000" y1="117.000000" y2="117.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="67" width="104" height="100%"><g transform="translate(0 167)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="172" style="font-size: 16px;">root > x</text></g>
|
||||
<style type="text/css"><![CDATA[
|
||||
.text {
|
||||
|
|
|
|||
|
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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-2692295619" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-2692295619" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
|
|
@ -94,7 +94,8 @@
|
|||
.d2-2692295619 .color-AB4{color:#EDF0FD;}
|
||||
.d2-2692295619 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="https://d2lang.com" xlink:href="https://d2lang.com"><g id="x"><g class="shape" ><rect x="17.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="59.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text><g transform="translate(86 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g></g></a><a href="https://terrastruct.com" xlink:href="https://terrastruct.com"><g id="y"><g class="shape" ><rect x="0.000000" y="166.000000" width="118.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="59.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text><g transform="translate(102 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now,
knowing I can't make my satellite dish PAYMENTS!</title><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">3</text></g></g></a><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 59.000000 68.000000 C 59.000000 106.000000 59.000000 126.000000 59.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2692295619)" /></g><mask id="d2-2692295619" maskUnits="userSpaceOnUse" x="-101" y="-118" width="337" height="451">
|
||||
<rect x="-101" y="-118" width="337" height="451" fill="white"></rect>
|
||||
|
||||
<rect x="55.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="54.500000" y="188.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask><line x1="-41.000000" x2="423.000000" y1="283.000000" y2="283.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="233" width="137" height="100%"><g transform="translate(0 333)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="338" style="font-size: 16px;">https://d2lang.com</text>
|
||||
<g transform="translate(0 385)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">2</text></g><text class="text" x="48" y="390" style="font-size: 16px;"><tspan x="48.000000" dy="0.000000">Gee, I feel kind of LIGHT in the head now,</tspan><tspan x="48.000000" dy="18.500000">knowing I can't make my satellite dish PAYMENTS!</tspan></text>
|
||||
<g transform="translate(0 442)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">3</text></g><text class="text" x="48" y="447" style="font-size: 16px;">https://terrastruct.com</text></g>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 661 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-2055261676" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 564 682"><svg id="d2-svg" class="d2-2055261676" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
|
|
@ -94,7 +94,8 @@
|
|||
.d2-2055261676 .color-AB4{color:#45475A;}
|
||||
.d2-2055261676 .color-AB5{color:#313244;}.appendix text.text{fill:#CDD6F4}.md{--color-fg-default:#CDD6F4;--color-fg-muted:#BAC2DE;--color-fg-subtle:#A6ADC8;--color-canvas-default:#1E1E2E;--color-canvas-subtle:#313244;--color-border-default:#CBA6f7;--color-border-muted:#CBA6f7;--color-neutral-muted:#313244;--color-accent-fg:#CBA6f7;--color-accent-emphasis:#CBA6f7;--color-attention-subtle:#BAC2DE;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B3{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AA4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N7{fill:url(#streaks-darker);mix-blend-mode:lighten}.light-code{display: none}.dark-code{display: block}]]></style><a href="https://d2lang.com" xlink:href="https://d2lang.com"><g id="x"><g class="shape" ><rect x="17.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="59.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text><g transform="translate(86 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g></g></a><a href="https://fosny.eu" xlink:href="https://fosny.eu"><g id="y"><g class="shape" ><rect x="0.000000" y="166.000000" width="118.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="59.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text><g transform="translate(102 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now,
knowing I can't make my satellite dish PAYMENTS!</title><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">3</text></g></g></a><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 59.000000 68.000000 C 59.000000 106.000000 59.000000 126.000000 59.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2055261676)" /></g><mask id="d2-2055261676" maskUnits="userSpaceOnUse" x="-101" y="-118" width="337" height="451">
|
||||
<rect x="-101" y="-118" width="337" height="451" fill="white"></rect>
|
||||
|
||||
<rect x="55.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="54.500000" y="188.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask><line x1="-41.000000" x2="423.000000" y1="283.000000" y2="283.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="233" width="137" height="100%"><g transform="translate(0 333)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="338" style="font-size: 16px;">https://d2lang.com</text>
|
||||
<g transform="translate(0 385)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">2</text></g><text class="text" x="48" y="390" style="font-size: 16px;"><tspan x="48.000000" dy="0.000000">Gee, I feel kind of LIGHT in the head now,</tspan><tspan x="48.000000" dy="18.500000">knowing I can't make my satellite dish PAYMENTS!</tspan></text>
|
||||
<g transform="translate(0 442)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">3</text></g><text class="text" x="48" y="447" style="font-size: 16px;">https://fosny.eu</text></g>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 661 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-820103664" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-820103664" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
|
|
@ -94,7 +94,8 @@
|
|||
.d2-820103664 .color-AB4{color:#EDF0FD;}
|
||||
.d2-820103664 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><rect x="1.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text><g transform="translate(70 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g><title>Total abstinence is easier than perfect moderation</title></g><g id="y"><g class="shape" ><rect x="0.000000" y="166.000000" width="86.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now,
knowing I can't make my satellite dish PAYMENTS!</title></g><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 43.000000 68.000000 C 43.000000 106.000000 43.000000 126.000000 43.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-820103664)" /></g><mask id="d2-820103664" maskUnits="userSpaceOnUse" x="-101" y="-118" width="305" height="451">
|
||||
<rect x="-101" y="-118" width="305" height="451" fill="white"></rect>
|
||||
|
||||
<rect x="39.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="38.500000" y="188.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask><line x1="-41.000000" x2="424.000000" y1="283.000000" y2="283.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="233" width="105" height="100%"><g transform="translate(0 333)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="338" style="font-size: 16px;">Total abstinence is easier than perfect moderation</text>
|
||||
<g transform="translate(0 385)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">2</text></g><text class="text" x="48" y="390" style="font-size: 16px;"><tspan x="48.000000" dy="0.000000">Gee, I feel kind of LIGHT in the head now,</tspan><tspan x="48.000000" dy="18.500000">knowing I can't make my satellite dish PAYMENTS!</tspan></text></g>
|
||||
<style type="text/css"><![CDATA[
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 660 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-820103664" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-820103664" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
|
|
@ -94,7 +94,8 @@
|
|||
.d2-820103664 .color-AB4{color:#EDF0FD;}
|
||||
.d2-820103664 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><rect x="1.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text><g transform="translate(70 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g><title>Total abstinence is easier than perfect moderation</title></g><g id="y"><g class="shape" ><rect x="0.000000" y="166.000000" width="86.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now,
knowing I can't make my satellite dish PAYMENTS!</title></g><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 43.000000 68.000000 C 43.000000 106.000000 43.000000 126.000000 43.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-820103664)" /></g><mask id="d2-820103664" maskUnits="userSpaceOnUse" x="-101" y="-118" width="305" height="451">
|
||||
<rect x="-101" y="-118" width="305" height="451" fill="white"></rect>
|
||||
|
||||
<rect x="39.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="38.500000" y="188.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask><line x1="-41.000000" x2="424.000000" y1="283.000000" y2="283.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="233" width="105" height="100%"><g transform="translate(0 333)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="338" style="font-size: 16px;">Total abstinence is easier than perfect moderation</text>
|
||||
<g transform="translate(0 385)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">2</text></g><text class="text" x="48" y="390" style="font-size: 16px;"><tspan x="48.000000" dy="0.000000">Gee, I feel kind of LIGHT in the head now,</tspan><tspan x="48.000000" dy="18.500000">knowing I can't make my satellite dish PAYMENTS!</tspan></text></g>
|
||||
<style type="text/css"><![CDATA[
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 660 KiB After Width: | Height: | Size: 661 KiB |
|
|
@ -456,11 +456,16 @@ func pathData(connection d2target.Connection, srcAdj, dstAdj *geo.Point) string
|
|||
return strings.Join(path, " ")
|
||||
}
|
||||
|
||||
func makeLabelMask(labelTL *geo.Point, width, height int) string {
|
||||
return fmt.Sprintf(`<rect x="%f" y="%f" width="%d" height="%d" fill="black"></rect>`,
|
||||
func makeLabelMask(labelTL *geo.Point, width, height int, opacity float64) string {
|
||||
fill := "black"
|
||||
if opacity != 1 {
|
||||
fill = fmt.Sprintf("rgba(0,0,0,%.2f)", opacity)
|
||||
}
|
||||
return fmt.Sprintf(`<rect x="%f" y="%f" width="%d" height="%d" fill="%s"></rect>`,
|
||||
labelTL.X, labelTL.Y,
|
||||
width,
|
||||
height,
|
||||
fill,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +515,9 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
|
|||
labelTL.Y = math.Round(labelTL.Y)
|
||||
|
||||
if label.Position(connection.LabelPosition).IsOnEdge() {
|
||||
labelMask = makeLabelMask(labelTL, connection.LabelWidth, connection.LabelHeight)
|
||||
labelMask = makeLabelMask(labelTL, connection.LabelWidth, connection.LabelHeight, 1)
|
||||
} else {
|
||||
labelMask = makeLabelMask(labelTL, connection.LabelWidth, connection.LabelHeight, 0.75)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1206,6 +1213,7 @@ func drawShape(writer io.Writer, diagramHash string, targetShape d2target.Shape,
|
|||
float64(targetShape.LabelWidth),
|
||||
float64(targetShape.LabelHeight),
|
||||
)
|
||||
labelMask = makeLabelMask(labelTL, targetShape.LabelWidth, targetShape.LabelHeight, 0.75)
|
||||
|
||||
fontClass := "text"
|
||||
if targetShape.FontFamily == "mono" {
|
||||
|
|
@ -1324,7 +1332,7 @@ func drawShape(writer io.Writer, diagramHash string, targetShape d2target.Shape,
|
|||
textEl.Content = RenderText(targetShape.Label, textEl.X, float64(targetShape.LabelHeight))
|
||||
fmt.Fprint(writer, textEl.Render())
|
||||
if targetShape.Blend {
|
||||
labelMask = makeLabelMask(labelTL, targetShape.LabelWidth, targetShape.LabelHeight-d2graph.INNER_LABEL_PADDING)
|
||||
labelMask = makeLabelMask(labelTL, targetShape.LabelWidth, targetShape.LabelHeight-d2graph.INNER_LABEL_PADDING, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 43 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-3655258321" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-3655258321" 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-3655258321 .text-bold {
|
||||
font-family: "d2-3655258321-font-bold";
|
||||
}
|
||||
|
|
@ -91,5 +91,6 @@
|
|||
.d2-3655258321 .color-AB4{color:#45475A;}
|
||||
.d2-3655258321 .color-AB5{color:#313244;}.appendix text.text{fill:#CDD6F4}.md{--color-fg-default:#CDD6F4;--color-fg-muted:#BAC2DE;--color-fg-subtle:#A6ADC8;--color-canvas-default:#1E1E2E;--color-canvas-subtle:#313244;--color-border-default:#CBA6f7;--color-border-muted:#CBA6f7;--color-neutral-muted:#313244;--color-accent-fg:#CBA6f7;--color-accent-emphasis:#CBA6f7;--color-attention-subtle:#BAC2DE;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B3{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AA4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N7{fill:url(#streaks-darker);mix-blend-mode:lighten}.light-code{display: none}.dark-code{display: block}]]></style><g id="a"><g class="shape" ><rect x="1.000000" y="0.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="28.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="55.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="27.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="(a -> b)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 27.500000 68.000000 C 27.500000 106.000000 27.500000 126.000000 27.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3655258321)" /></g><mask id="d2-3655258321" maskUnits="userSpaceOnUse" x="-101" y="-101" width="257" height="434">
|
||||
<rect x="-101" y="-101" width="257" height="434" fill="white"></rect>
|
||||
|
||||
<rect x="23.500000" y="22.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="188.500000" width="10" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 370 633"><svg id="d2-svg" class="d2-1784090246" width="370" height="633" viewBox="-101 -100 370 633"><rect x="-101.000000" y="-100.000000" width="370.000000" height="633.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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 370 633"><svg id="d2-svg" class="d2-1784090246" width="370" height="633" viewBox="-101 -100 370 633"><rect x="-101.000000" y="-100.000000" width="370.000000" height="633.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-1784090246 .text {
|
||||
font-family: "d2-1784090246-font-regular";
|
||||
}
|
||||
|
|
@ -98,5 +98,8 @@
|
|||
.d2-1784090246 .color-AB4{color:#45475A;}
|
||||
.d2-1784090246 .color-AB5{color:#313244;}.appendix text.text{fill:#CDD6F4}.md{--color-fg-default:#CDD6F4;--color-fg-muted:#BAC2DE;--color-fg-subtle:#A6ADC8;--color-canvas-default:#1E1E2E;--color-canvas-subtle:#313244;--color-border-default:#CBA6f7;--color-border-muted:#CBA6f7;--color-neutral-muted:#313244;--color-accent-fg:#CBA6f7;--color-accent-emphasis:#CBA6f7;--color-attention-subtle:#BAC2DE;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B3{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AA4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N7{fill:url(#streaks-darker);mix-blend-mode:lighten}.light-code{display: none}.dark-code{display: block}]]></style><g id="winter"><g class="shape" ><rect x="0.000000" y="44.000000" width="168.000000" height="122.000000" class=" stroke-B1 fill-B4" style="stroke-width:2;" /></g><text x="84.000000" y="28.000000" class="text fill-N1" style="text-anchor:middle;font-size:28px">winter</text></g><g id="summer"><g class="shape" ><rect x="7.000000" y="310.000000" width="155.000000" height="122.000000" class=" stroke-B1 fill-B4" style="stroke-width:2;" /></g><text x="84.500000" y="294.000000" class="text fill-N1" style="text-anchor:middle;font-size:28px">summer</text></g><g id="winter.snow"><g class="shape" ><rect x="40.000000" y="72.000000" width="88.000000" height="66.000000" class=" stroke-B1 fill-B5" style="stroke-width:2;" /></g><text x="84.000000" y="110.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">snow</text></g><g id="summer.sun"><g class="shape" ><rect x="47.000000" y="338.000000" width="75.000000" height="66.000000" class=" stroke-B1 fill-B5" style="stroke-width:2;" /></g><text x="84.500000" y="376.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">sun</text></g><g id="(winter.snow -> summer.sun)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 84.000000 140.000000 C 84.000000 160.399994 84.000000 176.000000 84.000000 191.000000 C 84.000000 206.000000 84.000000 280.399994 84.000000 334.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-1784090246)" /></g><mask id="d2-1784090246" maskUnits="userSpaceOnUse" x="-101" y="-100" width="370" height="633">
|
||||
<rect x="-101" y="-100" width="370" height="633" fill="white"></rect>
|
||||
|
||||
<rect x="43.000000" y="0.000000" width="82" height="39" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="33.000000" y="266.000000" width="103" height="39" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="62.500000" y="94.500000" width="43" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="69.500000" y="360.500000" width="30" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-3945613123" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-3945613123" 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-3945613123 .text-mono {
|
||||
font-family: "d2-3945613123-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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 937 410"><svg id="d2-svg" class="d2-82882857" width="937" height="410" viewBox="-101 -101 937 410"><rect x="-101.000000" y="-101.000000" width="937.000000" height="410.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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 937 410"><svg id="d2-svg" class="d2-82882857" width="937" height="410" viewBox="-101 -101 937 410"><rect x="-101.000000" y="-101.000000" width="937.000000" height="410.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-82882857 .text {
|
||||
font-family: "d2-82882857-font-regular";
|
||||
}
|
||||
|
|
@ -857,5 +857,7 @@
|
|||
</tspan></text><text class="text-mono" x="0" y="3.000000em" xml:space="preserve"><tspan fill="#fab387"></tspan><tspan fill="#cdd6f4">}</tspan></text></g></g></g><g id="text"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="352.000000" y="23.000000" width="383" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md"><p>Five is a sufficiently close approximation to infinity.</p>
|
||||
</div></foreignObject></g></g><g id="unknown"><g class="shape" ></g><g transform="translate(0.000000 170.000000)" class="light-code"><rect width="425.000000" height="38.000000" class="shape stroke-N1" style="fill:#ffffff" /><g transform="translate(6 6)"><text class="text-mono" x="0" y="1.000000em" xml:space="preserve">Don't hit me!!  I'm in the Twilight Zone!!!</text></g></g><g transform="translate(0.000000 170.000000)" class="dark-code"><rect width="425.000000" height="38.000000" class="shape stroke-N1" style="fill:#1e1e2e" /><g transform="translate(6 6)"><text class="text-mono" x="0" y="1.000000em" xml:space="preserve"><tspan fill="#fab387">Don't hit me!!  I'm in the Twilight Zone!!!</tspan></text></g></g></g><g id="(code -- unknown)[0]"><path d="M 212.500000 72.000000 C 212.500000 110.000000 212.500000 130.000000 212.500000 168.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" mask="url(#d2-82882857)" /></g><mask id="d2-82882857" maskUnits="userSpaceOnUse" x="-101" y="-101" width="937" height="410">
|
||||
<rect x="-101" y="-101" width="937" height="410" fill="white"></rect>
|
||||
|
||||
<rect x="133.000000" y="0.000000" width="154" height="65" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="352.000000" y="23.000000" width="383" height="24" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="0.000000" y="170.000000" width="420" height="33" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 457"><svg id="d2-svg" class="d2-1320785676" width="257" height="457" viewBox="-101 -101 257 457"><rect x="-101.000000" y="-101.000000" width="257.000000" height="457.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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 457"><svg id="d2-svg" class="d2-1320785676" width="257" height="457" viewBox="-101 -101 257 457"><rect x="-101.000000" y="-101.000000" width="257.000000" height="457.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-1320785676 .text-bold {
|
||||
font-family: "d2-1320785676-font-bold";
|
||||
}
|
||||
|
|
@ -98,5 +98,7 @@
|
|||
.d2-1320785676 .color-AB4{color:#45475A;}
|
||||
.d2-1320785676 .color-AB5{color:#313244;}.appendix text.text{fill:#CDD6F4}.md{--color-fg-default:#CDD6F4;--color-fg-muted:#BAC2DE;--color-fg-subtle:#A6ADC8;--color-canvas-default:#1E1E2E;--color-canvas-subtle:#313244;--color-border-default:#CBA6f7;--color-border-muted:#CBA6f7;--color-neutral-muted:#313244;--color-accent-fg:#CBA6f7;--color-accent-emphasis:#CBA6f7;--color-attention-subtle:#BAC2DE;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B3{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AA4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N7{fill:url(#streaks-darker);mix-blend-mode:lighten}.light-code{display: none}.dark-code{display: block}]]></style><g id="a"><g class="shape" ><rect x="1.000000" y="0.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="28.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="189.000000" width="55.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="27.500000" y="227.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="(a -> b)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 27.500000 68.000000 C 27.500000 115.199997 27.500000 139.899994 27.500000 185.500000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-1320785676)" /><text x="27.500000" y="132.000000" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">hello</text></g><mask id="d2-1320785676" maskUnits="userSpaceOnUse" x="-101" y="-101" width="257" height="457">
|
||||
<rect x="-101" y="-101" width="257" height="457" fill="white"></rect>
|
||||
<rect x="23.500000" y="22.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="211.500000" width="10" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="12.000000" y="116.000000" width="31" height="23" fill="black"></rect>
|
||||
</mask></svg></svg>
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-2779170942" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-2779170942" 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-2779170942 .text-bold {
|
||||
font-family: "d2-2779170942-font-bold";
|
||||
}
|
||||
|
|
@ -91,5 +91,8 @@
|
|||
.d2-2779170942 .color-AB4{color:#45475A;}
|
||||
.d2-2779170942 .color-AB5{color:#313244;}.appendix text.text{fill:#CDD6F4}.md{--color-fg-default:#CDD6F4;--color-fg-muted:#BAC2DE;--color-fg-subtle:#A6ADC8;--color-canvas-default:#1E1E2E;--color-canvas-subtle:#313244;--color-border-default:#CBA6f7;--color-border-muted:#CBA6f7;--color-neutral-muted:#313244;--color-accent-fg:#CBA6f7;--color-accent-emphasis:#CBA6f7;--color-attention-subtle:#BAC2DE;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B3{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AA4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N7{fill:url(#streaks-darker);mix-blend-mode:lighten}.light-code{display: none}.dark-code{display: block}]]></style><g id="bright"><g class="shape" ><rect x="0.000000" y="0.000000" width="94.000000" height="66.000000" stroke="#000" fill="#fff" style="stroke-width:2;" /></g><text x="47.000000" y="38.500000" fill="#000" class="text-bold" style="text-anchor:middle;font-size:16px">bright</text></g><g id="normal"><g class="shape" ><rect x="154.000000" y="0.000000" width="101.000000" height="66.000000" stroke="#000" fill="#ccc" style="stroke-width:2;" /></g><text x="204.500000" y="38.500000" fill="#000" class="text-bold" style="text-anchor:middle;font-size:16px">normal</text></g><g id="dark"><g class="shape" ><rect x="315.000000" y="0.000000" width="82.000000" height="66.000000" stroke="#000" fill="#555" style="stroke-width:2;" /></g><text x="356.000000" y="38.500000" fill="#fff" class="text-bold" style="text-anchor:middle;font-size:16px">dark</text></g><g id="darker"><g class="shape" ><rect x="457.000000" y="0.000000" width="99.000000" height="66.000000" stroke="#000" fill="#000" style="stroke-width:2;" /></g><text x="506.500000" y="38.500000" fill="#fff" class="text-bold" style="text-anchor:middle;font-size:16px">darker</text></g><mask id="d2-2779170942" maskUnits="userSpaceOnUse" x="-101" y="-101" width="758" height="268">
|
||||
<rect x="-101" y="-101" width="758" height="268" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="22.500000" width="49" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="176.500000" y="22.500000" width="56" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="337.500000" y="22.500000" width="37" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="479.500000" y="22.500000" width="54" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 104 KiB |
|
|
@ -74,18 +74,12 @@ func tableHeader(diagramHash string, shape d2target.Shape, box *geo.Box, text st
|
|||
return str
|
||||
}
|
||||
|
||||
func tableRow(shape d2target.Shape, box *geo.Box, nameText, typeText, constraintText string, fontSize, longestNameWidth float64) string {
|
||||
func tableRow(shape d2target.Shape, box *geo.Box, nameText, typeText, constraintText string, fontSize, longestNameWidth, longestTypeWidth float64) string {
|
||||
// Row is made up of name, type, and constraint
|
||||
// e.g. | diagram int FK |
|
||||
nameTL := label.InsideMiddleLeft.GetPointOnBox(
|
||||
box,
|
||||
d2target.NamePadding,
|
||||
box.Width,
|
||||
fontSize,
|
||||
)
|
||||
constraintTR := label.InsideMiddleRight.GetPointOnBox(
|
||||
box,
|
||||
d2target.TypePadding,
|
||||
0,
|
||||
fontSize,
|
||||
)
|
||||
|
|
@ -99,15 +93,14 @@ func tableRow(shape d2target.Shape, box *geo.Box, nameText, typeText, constraint
|
|||
textEl.Content = svg.EscapeText(nameText)
|
||||
out := textEl.Render()
|
||||
|
||||
textEl.X = nameTL.X + longestNameWidth + 2*d2target.NamePadding
|
||||
textEl.X += longestNameWidth + d2target.TypePadding
|
||||
textEl.Fill = shape.NeutralAccentColor
|
||||
textEl.Content = svg.EscapeText(typeText)
|
||||
out += textEl.Render()
|
||||
|
||||
textEl.X = constraintTR.X
|
||||
textEl.Y = constraintTR.Y + fontSize*3/4
|
||||
textEl.X = box.TopLeft.X + (box.Width - d2target.NamePadding)
|
||||
textEl.Fill = shape.SecondaryAccentColor
|
||||
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx;letter-spacing:2px", "end", fontSize)
|
||||
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "end", fontSize)
|
||||
textEl.Content = constraintText
|
||||
out += textEl.Render()
|
||||
|
||||
|
|
@ -144,15 +137,17 @@ func drawTable(writer io.Writer, diagramHash string, targetShape d2target.Shape)
|
|||
)
|
||||
|
||||
var longestNameWidth int
|
||||
var longestTypeWidth int
|
||||
for _, f := range targetShape.Columns {
|
||||
longestNameWidth = go2.Max(longestNameWidth, f.Name.LabelWidth)
|
||||
longestTypeWidth = go2.Max(longestTypeWidth, f.Type.LabelWidth)
|
||||
}
|
||||
|
||||
rowBox := geo.NewBox(box.TopLeft.Copy(), box.Width, rowHeight)
|
||||
rowBox.TopLeft.Y += headerBox.Height
|
||||
for idx, f := range targetShape.Columns {
|
||||
fmt.Fprint(writer,
|
||||
tableRow(targetShape, rowBox, f.Name.Label, f.Type.Label, f.ConstraintAbbr(), float64(targetShape.FontSize), float64(longestNameWidth)),
|
||||
tableRow(targetShape, rowBox, f.Name.Label, f.Type.Label, f.ConstraintAbbr(), float64(targetShape.FontSize), float64(longestNameWidth), float64(longestTypeWidth)),
|
||||
)
|
||||
rowBox.TopLeft.Y += rowHeight
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package d2target
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
NamePadding = 10
|
||||
TypePadding = 20
|
||||
HeaderPadding = 10
|
||||
NamePadding = 10
|
||||
TypePadding = 20
|
||||
ConstraintPadding = 20
|
||||
HeaderPadding = 10
|
||||
|
||||
// Setting table font size sets it for columns
|
||||
// The header needs to be a little larger for visual hierarchy
|
||||
|
|
@ -15,10 +18,10 @@ type SQLTable struct {
|
|||
}
|
||||
|
||||
type SQLColumn struct {
|
||||
Name Text `json:"name"`
|
||||
Type Text `json:"type"`
|
||||
Constraint string `json:"constraint"`
|
||||
Reference string `json:"reference"`
|
||||
Name Text `json:"name"`
|
||||
Type Text `json:"type"`
|
||||
Constraint []string `json:"constraint"`
|
||||
Reference string `json:"reference"`
|
||||
}
|
||||
|
||||
func (c SQLColumn) Texts(fontSize int) []*MText {
|
||||
|
|
@ -37,18 +40,31 @@ func (c SQLColumn) Texts(fontSize int) []*MText {
|
|||
IsItalic: false,
|
||||
Shape: "sql_table",
|
||||
},
|
||||
{
|
||||
Text: c.ConstraintAbbr(),
|
||||
FontSize: fontSize,
|
||||
IsBold: false,
|
||||
IsItalic: false,
|
||||
Shape: "sql_table",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c SQLColumn) ConstraintAbbr() string {
|
||||
switch c.Constraint {
|
||||
case "primary_key":
|
||||
return "PK"
|
||||
case "foreign_key":
|
||||
return "FK"
|
||||
case "unique":
|
||||
return "UNQ"
|
||||
default:
|
||||
return ""
|
||||
constraints := make([]string, len(c.Constraint))
|
||||
|
||||
for i, constraint := range c.Constraint {
|
||||
switch constraint {
|
||||
case "primary_key":
|
||||
constraint = "PK"
|
||||
case "foreign_key":
|
||||
constraint = "FK"
|
||||
case "unique":
|
||||
constraint = "UNQ"
|
||||
}
|
||||
|
||||
constraints[i] = constraint
|
||||
}
|
||||
|
||||
return strings.Join(constraints, ", ")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,14 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"oss.terrastruct.com/d2/d2cli"
|
||||
"oss.terrastruct.com/d2/lib/pptx"
|
||||
"oss.terrastruct.com/d2/lib/xgif"
|
||||
"oss.terrastruct.com/util-go/assert"
|
||||
"oss.terrastruct.com/util-go/diff"
|
||||
"oss.terrastruct.com/util-go/xmain"
|
||||
"oss.terrastruct.com/util-go/xos"
|
||||
|
||||
"oss.terrastruct.com/d2/d2cli"
|
||||
"oss.terrastruct.com/d2/lib/pptx"
|
||||
"oss.terrastruct.com/d2/lib/xgif"
|
||||
)
|
||||
|
||||
func TestCLI_E2E(t *testing.T) {
|
||||
|
|
@ -390,6 +391,64 @@ steps: {
|
|||
assert.Testdata(t, ".svg", svg)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "import",
|
||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||
writeFile(t, dir, "hello-world.d2", `x: @x; y: @y; ...@p`)
|
||||
writeFile(t, dir, "x.d2", `shape: circle`)
|
||||
writeFile(t, dir, "y.d2", `shape: square`)
|
||||
writeFile(t, dir, "p.d2", `x -> y`)
|
||||
err := runTestMain(t, ctx, dir, env, filepath.Join(dir, "hello-world.d2"))
|
||||
assert.Success(t, err)
|
||||
svg := readFile(t, dir, "hello-world.svg")
|
||||
assert.Testdata(t, ".svg", svg)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "import_spread_nested",
|
||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||
writeFile(t, dir, "hello-world.d2", `...@x.y`)
|
||||
writeFile(t, dir, "x.d2", `y: { jon; jan }`)
|
||||
err := runTestMain(t, ctx, dir, env, filepath.Join(dir, "hello-world.d2"))
|
||||
assert.Success(t, err)
|
||||
svg := readFile(t, dir, "hello-world.svg")
|
||||
assert.Testdata(t, ".svg", svg)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "chain_import",
|
||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||
writeFile(t, dir, "hello-world.d2", `...@x`)
|
||||
writeFile(t, dir, "x.d2", `...@y`)
|
||||
writeFile(t, dir, "y.d2", `meow`)
|
||||
err := runTestMain(t, ctx, dir, env, filepath.Join(dir, "hello-world.d2"))
|
||||
assert.Success(t, err)
|
||||
svg := readFile(t, dir, "hello-world.svg")
|
||||
assert.Testdata(t, ".svg", svg)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "board_import",
|
||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||
writeFile(t, dir, "hello-world.d2", `x.link: layers.x; layers: { x: @x }`)
|
||||
writeFile(t, dir, "x.d2", `y.link: layers.y; layers: { y: @y }`)
|
||||
writeFile(t, dir, "y.d2", `meow`)
|
||||
err := runTestMain(t, ctx, dir, env, filepath.Join(dir, "hello-world.d2"))
|
||||
assert.Success(t, err)
|
||||
t.Run("hello-world-x-y", func(t *testing.T) {
|
||||
svg := readFile(t, dir, "hello-world/x/y.svg")
|
||||
assert.Testdata(t, ".svg", svg)
|
||||
})
|
||||
t.Run("hello-world-x", func(t *testing.T) {
|
||||
svg := readFile(t, dir, "hello-world/x/index.svg")
|
||||
assert.Testdata(t, ".svg", svg)
|
||||
})
|
||||
t.Run("hello-world", func(t *testing.T) {
|
||||
svg := readFile(t, dir, "hello-world/index.svg")
|
||||
assert.Testdata(t, ".svg", svg)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
|
|
|||
|
|
@ -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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-855222762" 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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-855222762" 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-855222762 .text-bold {
|
||||
font-family: "d2-855222762-font-bold";
|
||||
}
|
||||
|
|
@ -91,5 +91,6 @@
|
|||
.d2-855222762 .color-AB4{color:#EDF0FD;}
|
||||
.d2-855222762 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><rect x="1.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="27.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g><g id="y"><g class="shape" ><rect x="0.000000" y="166.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="27.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 27.000000 68.000000 C 27.000000 106.000000 27.000000 126.000000 27.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-855222762)" /></g><mask id="d2-855222762" maskUnits="userSpaceOnUse" x="-101" y="-101" width="256" height="434">
|
||||
<rect x="-101" y="-101" width="256" height="434" fill="white"></rect>
|
||||
|
||||
<rect x="23.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="188.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.4 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.4.2-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.5.1-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-508224771 .text {
|
||||
font-family: "d2-508224771-font-regular";
|
||||
}
|
||||
|
|
@ -871,14 +871,20 @@
|
|||
}
|
||||
}]]></style><g style="animation: d2Transition-d2-508224771-0 5600ms infinite" class="d2-508224771" width="412" height="247" viewBox="-206 -166 412 247"><rect x="-206.000000" y="-166.000000" width="412.000000" height="247.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id=""Chicken's plan""><g class="shape" ></g><text x="0.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken's plan</text></g><mask id="d2-508224771" maskUnits="userSpaceOnUse" x="-206" y="-166" width="412" height="247">
|
||||
<rect x="-206" y="-166" width="412" height="247" fill="white"></rect>
|
||||
|
||||
<rect x="-105.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g><g style="animation: d2Transition-d2-508224771-1 5600ms infinite" class="d2-508224771" width="412" height="333" viewBox="-131 -166 412 333"><rect x="-131.000000" y="-166.000000" width="412.000000" height="333.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="Approach road"><g class="shape" ><rect x="0.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id=""Chicken's plan""><g class="shape" ></g><text x="75.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken's plan</text></g><mask id="d2-3302893893" maskUnits="userSpaceOnUse" x="-131" y="-166" width="412" height="333">
|
||||
<rect x="-131" y="-166" width="412" height="333" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="22.500000" width="105" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="-30.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g><g style="animation: d2Transition-d2-508224771-2 5600ms infinite" class="d2-508224771" width="412" height="499" viewBox="-131 -166 412 499"><rect x="-131.000000" y="-166.000000" width="412.000000" height="499.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="Approach road"><g class="shape" ><rect x="0.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id="Cross road"><g class="shape" ><rect x="15.000000" y="166.000000" width="120.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Cross road</text></g><g id=""Chicken's plan""><g class="shape" ></g><text x="75.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken's plan</text></g><g id="(Approach road -> Cross road)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 75.000000 68.000000 C 75.000000 106.000000 75.000000 126.000000 75.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2454480105)" /></g><mask id="d2-2454480105" maskUnits="userSpaceOnUse" x="-131" y="-166" width="412" height="499">
|
||||
<rect x="-131" y="-166" width="412" height="499" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="22.500000" width="105" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="37.500000" y="188.500000" width="75" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="-30.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g><g style="animation: d2Transition-d2-508224771-3 5600ms infinite" class="d2-508224771" width="412" height="665" viewBox="-104 -166 412 665"><rect x="-104.000000" y="-166.000000" width="412.000000" height="665.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="Approach road"><g class="shape" ><rect x="27.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="102.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id="Cross road"><g class="shape" ><rect x="42.000000" y="166.000000" width="120.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="102.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Cross road</text></g><g id="Make you wonder why"><g class="shape" ><rect x="0.000000" y="332.000000" width="203.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="101.500000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Make you wonder why</text></g><g id=""Chicken's plan""><g class="shape" ></g><text x="102.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken's plan</text></g><g id="(Approach road -> Cross road)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 101.500000 68.000000 C 101.500000 106.000000 101.500000 126.000000 101.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-682060979)" /></g><g id="(Cross road -> Make you wonder why)[0]"><path d="M 101.500000 234.000000 C 101.500000 272.000000 101.500000 292.000000 101.500000 328.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-682060979)" /></g><mask id="d2-682060979" maskUnits="userSpaceOnUse" x="-104" y="-166" width="412" height="665">
|
||||
<rect x="-104" y="-166" width="412" height="665" fill="white"></rect>
|
||||
|
||||
<rect x="49.500000" y="22.500000" width="105" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="64.500000" y="188.500000" width="75" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="354.500000" width="158" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="-3.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g></svg></svg>
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 32 KiB |
95
e2etests-cli/testdata/TestCLI_E2E/board_import/hello-world-x-y.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-685498927" 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-685498927 .text-bold {
|
||||
font-family: "d2-685498927-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-685498927-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-685498927 .fill-N1{fill:#0A0F25;}
|
||||
.d2-685498927 .fill-N2{fill:#676C7E;}
|
||||
.d2-685498927 .fill-N3{fill:#9499AB;}
|
||||
.d2-685498927 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-685498927 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-685498927 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-685498927 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-685498927 .fill-B1{fill:#0D32B2;}
|
||||
.d2-685498927 .fill-B2{fill:#0D32B2;}
|
||||
.d2-685498927 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-685498927 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-685498927 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-685498927 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-685498927 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-685498927 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-685498927 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-685498927 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-685498927 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-685498927 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-685498927 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-685498927 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-685498927 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-685498927 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-685498927 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-685498927 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-685498927 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-685498927 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-685498927 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-685498927 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-685498927 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-685498927 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-685498927 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-685498927 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-685498927 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-685498927 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-685498927 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-685498927 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-685498927 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-685498927 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-685498927 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-685498927 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-685498927 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-685498927 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-685498927 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-685498927 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-685498927 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-685498927 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-685498927 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-685498927 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-685498927 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-685498927 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-685498927 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-685498927 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-685498927 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-685498927 .color-N1{color:#0A0F25;}
|
||||
.d2-685498927 .color-N2{color:#676C7E;}
|
||||
.d2-685498927 .color-N3{color:#9499AB;}
|
||||
.d2-685498927 .color-N4{color:#CFD2DD;}
|
||||
.d2-685498927 .color-N5{color:#DEE1EB;}
|
||||
.d2-685498927 .color-N6{color:#EEF1F8;}
|
||||
.d2-685498927 .color-N7{color:#FFFFFF;}
|
||||
.d2-685498927 .color-B1{color:#0D32B2;}
|
||||
.d2-685498927 .color-B2{color:#0D32B2;}
|
||||
.d2-685498927 .color-B3{color:#E3E9FD;}
|
||||
.d2-685498927 .color-B4{color:#E3E9FD;}
|
||||
.d2-685498927 .color-B5{color:#EDF0FD;}
|
||||
.d2-685498927 .color-B6{color:#F7F8FE;}
|
||||
.d2-685498927 .color-AA2{color:#4A6FF3;}
|
||||
.d2-685498927 .color-AA4{color:#EDF0FD;}
|
||||
.d2-685498927 .color-AA5{color:#F7F8FE;}
|
||||
.d2-685498927 .color-AB4{color:#EDF0FD;}
|
||||
.d2-685498927 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="meow"><g class="shape" ><rect x="0.000000" y="0.000000" width="88.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="44.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">meow</text></g><mask id="d2-685498927" maskUnits="userSpaceOnUse" x="-101" y="-101" width="290" height="268">
|
||||
<rect x="-101" y="-101" width="290" height="268" fill="white"></rect>
|
||||
<rect x="22.500000" y="22.500000" width="43" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 8.8 KiB |
110
e2etests-cli/testdata/TestCLI_E2E/board_import/hello-world-x.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 305 285"><svg id="d2-svg" class="d2-2353227294" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
.d2-2353227294 .text-bold {
|
||||
font-family: "d2-2353227294-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-2353227294-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-2353227294 .fill-N1{fill:#0A0F25;}
|
||||
.d2-2353227294 .fill-N2{fill:#676C7E;}
|
||||
.d2-2353227294 .fill-N3{fill:#9499AB;}
|
||||
.d2-2353227294 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-2353227294 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-2353227294 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-2353227294 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-2353227294 .fill-B1{fill:#0D32B2;}
|
||||
.d2-2353227294 .fill-B2{fill:#0D32B2;}
|
||||
.d2-2353227294 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-2353227294 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-2353227294 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-2353227294 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-2353227294 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-2353227294 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-2353227294 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-2353227294 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-2353227294 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-2353227294 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-2353227294 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-2353227294 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-2353227294 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-2353227294 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-2353227294 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-2353227294 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-2353227294 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-2353227294 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-2353227294 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-2353227294 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-2353227294 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-2353227294 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-2353227294 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-2353227294 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-2353227294 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-2353227294 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-2353227294 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-2353227294 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-2353227294 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-2353227294 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-2353227294 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-2353227294 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-2353227294 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-2353227294 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-2353227294 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-2353227294 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-2353227294 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-2353227294 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-2353227294 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-2353227294 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-2353227294 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-2353227294 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-2353227294 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-2353227294 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-2353227294 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-2353227294 .color-N1{color:#0A0F25;}
|
||||
.d2-2353227294 .color-N2{color:#676C7E;}
|
||||
.d2-2353227294 .color-N3{color:#9499AB;}
|
||||
.d2-2353227294 .color-N4{color:#CFD2DD;}
|
||||
.d2-2353227294 .color-N5{color:#DEE1EB;}
|
||||
.d2-2353227294 .color-N6{color:#EEF1F8;}
|
||||
.d2-2353227294 .color-N7{color:#FFFFFF;}
|
||||
.d2-2353227294 .color-B1{color:#0D32B2;}
|
||||
.d2-2353227294 .color-B2{color:#0D32B2;}
|
||||
.d2-2353227294 .color-B3{color:#E3E9FD;}
|
||||
.d2-2353227294 .color-B4{color:#E3E9FD;}
|
||||
.d2-2353227294 .color-B5{color:#EDF0FD;}
|
||||
.d2-2353227294 .color-B6{color:#F7F8FE;}
|
||||
.d2-2353227294 .color-AA2{color:#4A6FF3;}
|
||||
.d2-2353227294 .color-AA4{color:#EDF0FD;}
|
||||
.d2-2353227294 .color-AA5{color:#F7F8FE;}
|
||||
.d2-2353227294 .color-AB4{color:#EDF0FD;}
|
||||
.d2-2353227294 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="y.svg" xlink:href="y.svg"><g id="y"><g class="shape" ><rect x="0.000000" y="0.000000" width="86.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text><g transform="translate(70 -16)" class="appendix-icon"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3440_35088111)">
|
||||
<path d="M16 31.1109C24.3456 31.1109 31.1111 24.3454 31.1111 15.9998C31.1111 7.65415 24.3456 0.888672 16 0.888672C7.65436 0.888672 0.888885 7.65415 0.888885 15.9998C0.888885 24.3454 7.65436 31.1109 16 31.1109Z" fill="white" stroke="#DEE1EB"/>
|
||||
<path d="M14.3909 16.7965C14.7364 17.2584 15.1772 17.6406 15.6834 17.9171C16.1896 18.1938 16.7494 18.3582 17.3248 18.3993C17.9001 18.4405 18.4777 18.3575 19.0181 18.1559C19.5586 17.9543 20.0492 17.6389 20.4571 17.2309L22.8708 14.8173C23.6036 14.0586 24.0089 13.0425 23.9998 11.9877C23.9906 10.933 23.5676 9.92404 22.8217 9.17821C22.0759 8.43237 21.067 8.00931 20.0123 8.00015C18.9575 7.99098 17.9413 8.39644 17.1827 9.1292L15.7988 10.505" stroke="#2E3346" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M17.609 15.1874C17.2635 14.7255 16.8227 14.3433 16.3165 14.0667C15.8103 13.7902 15.2505 13.6257 14.6752 13.5845C14.0998 13.5433 13.5223 13.6263 12.9819 13.8279C12.4414 14.0295 11.9506 14.345 11.5428 14.753L9.1292 17.1666C8.39644 17.9252 7.99098 18.9414 8.00015 19.9962C8.00931 21.0509 8.43237 22.0598 9.17821 22.8056C9.92405 23.5515 10.933 23.9745 11.9877 23.9837C13.0425 23.9928 14.0586 23.5875 14.8173 22.8547L16.193 21.4788" stroke="#2E3346" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3440_35088111">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</g></g></a><mask id="d2-2353227294" maskUnits="userSpaceOnUse" x="-101" y="-118" width="305" height="285">
|
||||
<rect x="-101" y="-118" width="305" height="285" fill="white"></rect>
|
||||
<rect x="38.500000" y="22.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
110
e2etests-cli/testdata/TestCLI_E2E/board_import/hello-world.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 285"><svg id="d2-svg" class="d2-2067460405" 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 {
|
||||
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
|
||||
}
|
||||
.d2-2067460405 .text-bold {
|
||||
font-family: "d2-2067460405-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-2067460405-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-2067460405 .fill-N1{fill:#0A0F25;}
|
||||
.d2-2067460405 .fill-N2{fill:#676C7E;}
|
||||
.d2-2067460405 .fill-N3{fill:#9499AB;}
|
||||
.d2-2067460405 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-2067460405 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-2067460405 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-2067460405 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-2067460405 .fill-B1{fill:#0D32B2;}
|
||||
.d2-2067460405 .fill-B2{fill:#0D32B2;}
|
||||
.d2-2067460405 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-2067460405 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-2067460405 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-2067460405 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-2067460405 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-2067460405 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-2067460405 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-2067460405 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-2067460405 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-2067460405 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-2067460405 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-2067460405 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-2067460405 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-2067460405 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-2067460405 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-2067460405 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-2067460405 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-2067460405 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-2067460405 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-2067460405 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-2067460405 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-2067460405 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-2067460405 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-2067460405 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-2067460405 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-2067460405 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-2067460405 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-2067460405 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-2067460405 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-2067460405 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-2067460405 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-2067460405 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-2067460405 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-2067460405 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-2067460405 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-2067460405 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-2067460405 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-2067460405 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-2067460405 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-2067460405 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-2067460405 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-2067460405 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-2067460405 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-2067460405 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-2067460405 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-2067460405 .color-N1{color:#0A0F25;}
|
||||
.d2-2067460405 .color-N2{color:#676C7E;}
|
||||
.d2-2067460405 .color-N3{color:#9499AB;}
|
||||
.d2-2067460405 .color-N4{color:#CFD2DD;}
|
||||
.d2-2067460405 .color-N5{color:#DEE1EB;}
|
||||
.d2-2067460405 .color-N6{color:#EEF1F8;}
|
||||
.d2-2067460405 .color-N7{color:#FFFFFF;}
|
||||
.d2-2067460405 .color-B1{color:#0D32B2;}
|
||||
.d2-2067460405 .color-B2{color:#0D32B2;}
|
||||
.d2-2067460405 .color-B3{color:#E3E9FD;}
|
||||
.d2-2067460405 .color-B4{color:#E3E9FD;}
|
||||
.d2-2067460405 .color-B5{color:#EDF0FD;}
|
||||
.d2-2067460405 .color-B6{color:#F7F8FE;}
|
||||
.d2-2067460405 .color-AA2{color:#4A6FF3;}
|
||||
.d2-2067460405 .color-AA4{color:#EDF0FD;}
|
||||
.d2-2067460405 .color-AA5{color:#F7F8FE;}
|
||||
.d2-2067460405 .color-AB4{color:#EDF0FD;}
|
||||
.d2-2067460405 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="x/index.svg" xlink:href="x/index.svg"><g id="x"><g class="shape" ><rect x="0.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="42.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text><g transform="translate(69 -16)" class="appendix-icon"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3440_35088111)">
|
||||
<path d="M16 31.1109C24.3456 31.1109 31.1111 24.3454 31.1111 15.9998C31.1111 7.65415 24.3456 0.888672 16 0.888672C7.65436 0.888672 0.888885 7.65415 0.888885 15.9998C0.888885 24.3454 7.65436 31.1109 16 31.1109Z" fill="white" stroke="#DEE1EB"/>
|
||||
<path d="M14.3909 16.7965C14.7364 17.2584 15.1772 17.6406 15.6834 17.9171C16.1896 18.1938 16.7494 18.3582 17.3248 18.3993C17.9001 18.4405 18.4777 18.3575 19.0181 18.1559C19.5586 17.9543 20.0492 17.6389 20.4571 17.2309L22.8708 14.8173C23.6036 14.0586 24.0089 13.0425 23.9998 11.9877C23.9906 10.933 23.5676 9.92404 22.8217 9.17821C22.0759 8.43237 21.067 8.00931 20.0123 8.00015C18.9575 7.99098 17.9413 8.39644 17.1827 9.1292L15.7988 10.505" stroke="#2E3346" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M17.609 15.1874C17.2635 14.7255 16.8227 14.3433 16.3165 14.0667C15.8103 13.7902 15.2505 13.6257 14.6752 13.5845C14.0998 13.5433 13.5223 13.6263 12.9819 13.8279C12.4414 14.0295 11.9506 14.345 11.5428 14.753L9.1292 17.1666C8.39644 17.9252 7.99098 18.9414 8.00015 19.9962C8.00931 21.0509 8.43237 22.0598 9.17821 22.8056C9.92405 23.5515 10.933 23.9745 11.9877 23.9837C13.0425 23.9928 14.0586 23.5875 14.8173 22.8547L16.193 21.4788" stroke="#2E3346" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3440_35088111">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</g></g></a><mask id="d2-2067460405" maskUnits="userSpaceOnUse" x="-101" y="-118" width="304" height="285">
|
||||
<rect x="-101" y="-118" width="304" height="285" fill="white"></rect>
|
||||
<rect x="38.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
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.4.2-HEAD" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-855222762" 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.5.1-HEAD" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-855222762" 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-855222762 .text-bold {
|
||||
font-family: "d2-855222762-font-bold";
|
||||
}
|
||||
|
|
@ -91,5 +91,6 @@
|
|||
.d2-855222762 .color-AB4{color:#EDF0FD;}
|
||||
.d2-855222762 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><rect x="1.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="27.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g><g id="y"><g class="shape" ><rect x="0.000000" y="166.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="27.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 27.000000 68.000000 C 27.000000 106.000000 27.000000 126.000000 27.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-855222762)" /></g><mask id="d2-855222762" maskUnits="userSpaceOnUse" x="-101" y="-101" width="256" height="434">
|
||||
<rect x="-101" y="-101" width="256" height="434" fill="white"></rect>
|
||||
|
||||
<rect x="23.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="188.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.4 KiB |
95
e2etests-cli/testdata/TestCLI_E2E/chain_import.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-685498927" 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-685498927 .text-bold {
|
||||
font-family: "d2-685498927-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-685498927-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-685498927 .fill-N1{fill:#0A0F25;}
|
||||
.d2-685498927 .fill-N2{fill:#676C7E;}
|
||||
.d2-685498927 .fill-N3{fill:#9499AB;}
|
||||
.d2-685498927 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-685498927 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-685498927 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-685498927 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-685498927 .fill-B1{fill:#0D32B2;}
|
||||
.d2-685498927 .fill-B2{fill:#0D32B2;}
|
||||
.d2-685498927 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-685498927 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-685498927 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-685498927 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-685498927 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-685498927 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-685498927 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-685498927 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-685498927 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-685498927 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-685498927 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-685498927 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-685498927 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-685498927 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-685498927 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-685498927 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-685498927 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-685498927 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-685498927 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-685498927 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-685498927 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-685498927 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-685498927 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-685498927 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-685498927 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-685498927 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-685498927 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-685498927 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-685498927 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-685498927 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-685498927 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-685498927 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-685498927 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-685498927 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-685498927 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-685498927 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-685498927 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-685498927 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-685498927 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-685498927 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-685498927 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-685498927 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-685498927 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-685498927 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-685498927 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-685498927 .color-N1{color:#0A0F25;}
|
||||
.d2-685498927 .color-N2{color:#676C7E;}
|
||||
.d2-685498927 .color-N3{color:#9499AB;}
|
||||
.d2-685498927 .color-N4{color:#CFD2DD;}
|
||||
.d2-685498927 .color-N5{color:#DEE1EB;}
|
||||
.d2-685498927 .color-N6{color:#EEF1F8;}
|
||||
.d2-685498927 .color-N7{color:#FFFFFF;}
|
||||
.d2-685498927 .color-B1{color:#0D32B2;}
|
||||
.d2-685498927 .color-B2{color:#0D32B2;}
|
||||
.d2-685498927 .color-B3{color:#E3E9FD;}
|
||||
.d2-685498927 .color-B4{color:#E3E9FD;}
|
||||
.d2-685498927 .color-B5{color:#EDF0FD;}
|
||||
.d2-685498927 .color-B6{color:#F7F8FE;}
|
||||
.d2-685498927 .color-AA2{color:#4A6FF3;}
|
||||
.d2-685498927 .color-AA4{color:#EDF0FD;}
|
||||
.d2-685498927 .color-AA5{color:#F7F8FE;}
|
||||
.d2-685498927 .color-AB4{color:#EDF0FD;}
|
||||
.d2-685498927 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="meow"><g class="shape" ><rect x="0.000000" y="0.000000" width="88.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="44.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">meow</text></g><mask id="d2-685498927" maskUnits="userSpaceOnUse" x="-101" y="-101" width="290" height="268">
|
||||
<rect x="-101" y="-101" width="290" height="268" fill="white"></rect>
|
||||
<rect x="22.500000" y="22.500000" width="43" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 8.8 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.4.2-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.5.1-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-1644916896 .text-bold {
|
||||
font-family: "d2-1644916896-font-bold";
|
||||
}
|
||||
|
|
@ -118,11 +118,19 @@
|
|||
}
|
||||
}]]></style><g style="animation: d2Transition-d2-1644916896-0 4200ms infinite" class="d2-1644916896" width="255" height="434" viewBox="-101 -101 255 434"><rect x="-101.000000" y="-101.000000" width="255.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="(a -> b)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-746933975)" /></g><mask id="d2-746933975" maskUnits="userSpaceOnUse" x="-101" y="-101" width="255" height="434">
|
||||
<rect x="-101" y="-101" width="255" height="434" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g><g style="animation: d2Transition-d2-1644916896-1 4200ms infinite" class="d2-1644916896" width="368" height="600" viewBox="-101 -101 368 600"><rect x="-101.000000" y="-101.000000" width="368.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="d"><g class="shape" ><rect x="56.000000" y="332.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.000000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">d</text></g><g id="c"><g class="shape" ><rect x="113.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="139.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">c</text></g><g id="(a -> b)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-919984524)" /></g><g id="(b -> d)[0]"><path d="M 26.500000 234.000000 C 26.500000 272.000000 33.299999 292.000000 58.250760 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-919984524)" /></g><g id="(c -> d)[0]"><path d="M 139.500000 234.000000 C 139.500000 272.000000 132.699997 292.000000 107.749240 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-919984524)" /></g><mask id="d2-919984524" maskUnits="userSpaceOnUse" x="-101" y="-101" width="368" height="600">
|
||||
<rect x="-101" y="-101" width="368" height="600" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="78.500000" y="354.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="135.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g><g style="animation: d2Transition-d2-1644916896-2 4200ms infinite" class="d2-1644916896" width="368" height="766" viewBox="-101 -101 368 766"><rect x="-101.000000" y="-101.000000" width="368.000000" height="766.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="d"><g class="shape" ><rect x="56.000000" y="332.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.000000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">d</text></g><g id="c"><g class="shape" ><rect x="113.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="139.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">c</text></g><g id="e"><g class="shape" ><rect x="57.000000" y="498.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.500000" y="536.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">e</text></g><g id="(a -> b)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-348119987)" /></g><g id="(b -> d)[0]"><path d="M 26.500000 234.000000 C 26.500000 272.000000 33.299999 292.000000 58.250760 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-348119987)" /></g><g id="(c -> d)[0]"><path d="M 139.500000 234.000000 C 139.500000 272.000000 132.699997 292.000000 107.749240 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-348119987)" /></g><g id="(d -> e)[0]"><path d="M 83.000000 400.000000 C 83.000000 438.000000 83.000000 458.000000 83.000000 494.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-348119987)" /></g><mask id="d2-348119987" maskUnits="userSpaceOnUse" x="-101" y="-101" width="368" height="766">
|
||||
<rect x="-101" y="-101" width="368" height="766" fill="white"></rect>
|
||||
|
||||
<rect x="22.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="22.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="78.500000" y="354.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="135.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="79.500000" y="520.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></g></svg></svg>
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 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.4.2-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 200 200"><svg id="d2-svg" class="d2-121760133" width="200" height="200" viewBox="-100 -100 200 200"><rect x="-100.000000" y="-100.000000" width="200.000000" height="200.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[]]></style><style type="text/css"><![CDATA[.shape {
|
||||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 200 200"><svg id="d2-svg" class="d2-121760133" width="200" height="200" viewBox="-100 -100 200 200"><rect x="-100.000000" y="-100.000000" width="200.000000" height="200.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 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 |
96
e2etests-cli/testdata/TestCLI_E2E/import.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 271 437"><svg id="d2-svg" class="d2-1393279198" width="271" height="437" viewBox="-101 -101 271 437"><rect x="-101.000000" y="-101.000000" width="271.000000" height="437.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-1393279198 .text-bold {
|
||||
font-family: "d2-1393279198-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-1393279198-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-1393279198 .fill-N1{fill:#0A0F25;}
|
||||
.d2-1393279198 .fill-N2{fill:#676C7E;}
|
||||
.d2-1393279198 .fill-N3{fill:#9499AB;}
|
||||
.d2-1393279198 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-1393279198 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-1393279198 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-1393279198 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-1393279198 .fill-B1{fill:#0D32B2;}
|
||||
.d2-1393279198 .fill-B2{fill:#0D32B2;}
|
||||
.d2-1393279198 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-1393279198 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-1393279198 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-1393279198 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-1393279198 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-1393279198 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-1393279198 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-1393279198 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-1393279198 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-1393279198 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-1393279198 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-1393279198 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-1393279198 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-1393279198 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-1393279198 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-1393279198 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-1393279198 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-1393279198 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-1393279198 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-1393279198 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-1393279198 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-1393279198 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-1393279198 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-1393279198 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-1393279198 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-1393279198 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-1393279198 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-1393279198 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-1393279198 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-1393279198 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-1393279198 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-1393279198 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-1393279198 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-1393279198 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-1393279198 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-1393279198 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-1393279198 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-1393279198 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-1393279198 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-1393279198 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-1393279198 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-1393279198 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-1393279198 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-1393279198 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-1393279198 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-1393279198 .color-N1{color:#0A0F25;}
|
||||
.d2-1393279198 .color-N2{color:#676C7E;}
|
||||
.d2-1393279198 .color-N3{color:#9499AB;}
|
||||
.d2-1393279198 .color-N4{color:#CFD2DD;}
|
||||
.d2-1393279198 .color-N5{color:#DEE1EB;}
|
||||
.d2-1393279198 .color-N6{color:#EEF1F8;}
|
||||
.d2-1393279198 .color-N7{color:#FFFFFF;}
|
||||
.d2-1393279198 .color-B1{color:#0D32B2;}
|
||||
.d2-1393279198 .color-B2{color:#0D32B2;}
|
||||
.d2-1393279198 .color-B3{color:#E3E9FD;}
|
||||
.d2-1393279198 .color-B4{color:#E3E9FD;}
|
||||
.d2-1393279198 .color-B5{color:#EDF0FD;}
|
||||
.d2-1393279198 .color-B6{color:#F7F8FE;}
|
||||
.d2-1393279198 .color-AA2{color:#4A6FF3;}
|
||||
.d2-1393279198 .color-AA4{color:#EDF0FD;}
|
||||
.d2-1393279198 .color-AA5{color:#F7F8FE;}
|
||||
.d2-1393279198 .color-AB4{color:#EDF0FD;}
|
||||
.d2-1393279198 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><ellipse rx="34.500000" ry="34.500000" cx="34.500000" cy="34.500000" class="shape stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="34.500000" y="40.000000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g><g id="y"><g class="shape" ><rect x="2.000000" y="169.000000" width="66.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="35.000000" y="207.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g><g id="(x -> y)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 34.980001 70.999900 C 34.599998 109.000000 34.500000 129.000000 34.500000 165.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-1393279198)" /></g><mask id="d2-1393279198" maskUnits="userSpaceOnUse" x="-101" y="-101" width="271" height="437">
|
||||
<rect x="-101" y="-101" width="271" height="437" fill="white"></rect>
|
||||
<rect x="30.500000" y="24.000000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="30.500000" y="191.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
96
e2etests-cli/testdata/TestCLI_E2E/import_spread_nested.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
<?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.5.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 399 268"><svg id="d2-svg" class="d2-3967102011" width="399" height="268" viewBox="-101 -101 399 268"><rect x="-101.000000" y="-101.000000" width="399.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-3967102011 .text-bold {
|
||||
font-family: "d2-3967102011-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-3967102011-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-3967102011 .fill-N1{fill:#0A0F25;}
|
||||
.d2-3967102011 .fill-N2{fill:#676C7E;}
|
||||
.d2-3967102011 .fill-N3{fill:#9499AB;}
|
||||
.d2-3967102011 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-3967102011 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-3967102011 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-3967102011 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-3967102011 .fill-B1{fill:#0D32B2;}
|
||||
.d2-3967102011 .fill-B2{fill:#0D32B2;}
|
||||
.d2-3967102011 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-3967102011 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-3967102011 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-3967102011 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-3967102011 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-3967102011 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-3967102011 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-3967102011 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-3967102011 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-3967102011 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-3967102011 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-3967102011 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-3967102011 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-3967102011 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-3967102011 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-3967102011 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-3967102011 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-3967102011 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-3967102011 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-3967102011 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-3967102011 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-3967102011 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-3967102011 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-3967102011 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-3967102011 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-3967102011 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-3967102011 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-3967102011 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-3967102011 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-3967102011 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-3967102011 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-3967102011 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-3967102011 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-3967102011 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-3967102011 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-3967102011 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-3967102011 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-3967102011 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-3967102011 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-3967102011 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-3967102011 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-3967102011 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-3967102011 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-3967102011 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-3967102011 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-3967102011 .color-N1{color:#0A0F25;}
|
||||
.d2-3967102011 .color-N2{color:#676C7E;}
|
||||
.d2-3967102011 .color-N3{color:#9499AB;}
|
||||
.d2-3967102011 .color-N4{color:#CFD2DD;}
|
||||
.d2-3967102011 .color-N5{color:#DEE1EB;}
|
||||
.d2-3967102011 .color-N6{color:#EEF1F8;}
|
||||
.d2-3967102011 .color-N7{color:#FFFFFF;}
|
||||
.d2-3967102011 .color-B1{color:#0D32B2;}
|
||||
.d2-3967102011 .color-B2{color:#0D32B2;}
|
||||
.d2-3967102011 .color-B3{color:#E3E9FD;}
|
||||
.d2-3967102011 .color-B4{color:#E3E9FD;}
|
||||
.d2-3967102011 .color-B5{color:#EDF0FD;}
|
||||
.d2-3967102011 .color-B6{color:#F7F8FE;}
|
||||
.d2-3967102011 .color-AA2{color:#4A6FF3;}
|
||||
.d2-3967102011 .color-AA4{color:#EDF0FD;}
|
||||
.d2-3967102011 .color-AA5{color:#F7F8FE;}
|
||||
.d2-3967102011 .color-AB4{color:#EDF0FD;}
|
||||
.d2-3967102011 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="jon"><g class="shape" ><rect x="0.000000" y="0.000000" width="69.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="34.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">jon</text></g><g id="jan"><g class="shape" ><rect x="129.000000" y="0.000000" width="68.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="163.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">jan</text></g><mask id="d2-3967102011" maskUnits="userSpaceOnUse" x="-101" y="-101" width="399" height="268">
|
||||
<rect x="-101" y="-101" width="399" height="268" fill="white"></rect>
|
||||
<rect x="22.500000" y="22.500000" width="24" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="151.500000" y="22.500000" width="23" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |