Skip to content

Commit

Permalink
Merge pull request #1116 from alixander/svg-link
Browse files Browse the repository at this point in the history
svg link
  • Loading branch information
alixander authored Mar 31, 2023
2 parents 8f01c77 + 1646fc0 commit a53eb48
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#### Features 🚀

- Multi-board SVG outputs with internal links go to their output paths [#1116](https://github.com/terrastruct/d2/pull/1116)

#### Improvements 🧹

#### Bugfixes ⛑️
Expand Down
102 changes: 102 additions & 0 deletions d2cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,15 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, rende
return pdf, true, nil
} else {
compileDur := time.Since(start)
if animateInterval <= 0 {
// Rename all the "root.layers.x" to the paths that the boards get output to
linkToOutput, err := resolveLinks("root", outputPath, diagram)
if err != nil {
return nil, false, err
}
relink(diagram, linkToOutput)
}

boards, err := render(ctx, ms, compileDur, plugin, renderOpts, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram)
if err != nil {
return nil, false, err
Expand All @@ -382,6 +391,99 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, rende
}
}

func resolveLinks(currDiagramPath, outputPath string, diagram *d2target.Diagram) (linkToOutput map[string]string, err error) {
if diagram.Name != "" {
ext := filepath.Ext(outputPath)
outputPath = strings.TrimSuffix(outputPath, ext)
outputPath = filepath.Join(outputPath, diagram.Name)
outputPath += ext
}

boardOutputPath := outputPath
if len(diagram.Layers) > 0 || len(diagram.Scenarios) > 0 || len(diagram.Steps) > 0 {
ext := filepath.Ext(boardOutputPath)
boardOutputPath = strings.TrimSuffix(boardOutputPath, ext)
boardOutputPath = filepath.Join(boardOutputPath, "index")
boardOutputPath += ext
}

layersOutputPath := outputPath
if len(diagram.Scenarios) > 0 || len(diagram.Steps) > 0 {
ext := filepath.Ext(layersOutputPath)
layersOutputPath = strings.TrimSuffix(layersOutputPath, ext)
layersOutputPath = filepath.Join(layersOutputPath, "layers")
layersOutputPath += ext
}
scenariosOutputPath := outputPath
if len(diagram.Layers) > 0 || len(diagram.Steps) > 0 {
ext := filepath.Ext(scenariosOutputPath)
scenariosOutputPath = strings.TrimSuffix(scenariosOutputPath, ext)
scenariosOutputPath = filepath.Join(scenariosOutputPath, "scenarios")
scenariosOutputPath += ext
}
stepsOutputPath := outputPath
if len(diagram.Layers) > 0 || len(diagram.Scenarios) > 0 {
ext := filepath.Ext(stepsOutputPath)
stepsOutputPath = strings.TrimSuffix(stepsOutputPath, ext)
stepsOutputPath = filepath.Join(stepsOutputPath, "steps")
stepsOutputPath += ext
}

linkToOutput = map[string]string{currDiagramPath: boardOutputPath}

for _, dl := range diagram.Layers {
m, err := resolveLinks(strings.Join([]string{currDiagramPath, "layers", dl.Name}, "."), layersOutputPath, dl)
if err != nil {
return nil, err
}
for k, v := range m {
linkToOutput[k] = v
}
}
for _, dl := range diagram.Scenarios {
m, err := resolveLinks(strings.Join([]string{currDiagramPath, "scenarios", dl.Name}, "."), scenariosOutputPath, dl)
if err != nil {
return nil, err
}
for k, v := range m {
linkToOutput[k] = v
}
}
for _, dl := range diagram.Steps {
m, err := resolveLinks(strings.Join([]string{currDiagramPath, "steps", dl.Name}, "."), stepsOutputPath, dl)
if err != nil {
return nil, err
}
for k, v := range m {
linkToOutput[k] = v
}
}

return linkToOutput, nil
}

func relink(d *d2target.Diagram, linkToOutput map[string]string) {
for i, shape := range d.Shapes {
if shape.Link != "" {
for k, v := range linkToOutput {
if shape.Link == k {
d.Shapes[i].Link = v
break
}
}
}
}
for _, board := range d.Layers {
relink(board, linkToOutput)
}
for _, board := range d.Scenarios {
relink(board, linkToOutput)
}
for _, board := range d.Steps {
relink(board, linkToOutput)
}
}

func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plugin d2plugin.Plugin, opts d2svg.RenderOpts, inputPath, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([][]byte, error) {
if diagram.Name != "" {
ext := filepath.Ext(outputPath)
Expand Down
33 changes: 33 additions & 0 deletions e2etests-cli/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func TestCLI_E2E(t *testing.T) {
tca := []struct {
name string
skipCI bool
skip bool
run func(t *testing.T, ctx context.Context, dir string, env *xos.Env)
}{
{
Expand Down Expand Up @@ -82,6 +83,35 @@ steps: {
assert.Testdata(t, ".svg", svg)
},
},
{
name: "linked-path",
// TODO tempdir is random, resulting in different test results each time with the links
skip: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "linked.d2", `cat: how does the cat go? {
link: layers.cat
}
layers: {
cat: {
home: {
link: _
}
the cat -> meow: goes
scenarios: {
big cat: {
the cat -> roar: goes
}
}
}
}
`)
err := runTestMain(t, ctx, dir, env, "linked.d2")
assert.Success(t, err)

assert.TestdataDir(t, filepath.Join(dir, "linked"))
},
},
{
name: "with-font",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
Expand Down Expand Up @@ -241,6 +271,9 @@ layers: {
if tc.skipCI && os.Getenv("CI") != "" {
t.SkipNow()
}
if tc.skip {
t.SkipNow()
}

ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
defer cancel()
Expand Down
Binary file modified e2etests-cli/testdata/TestCLI_E2E/internal_linked_pdf.exp.pdf
Binary file not shown.

0 comments on commit a53eb48

Please sign in to comment.