commit
a53eb48676
4 changed files with 137 additions and 0 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
#### Features 🚀
|
#### Features 🚀
|
||||||
|
|
||||||
|
- Multi-board SVG outputs with internal links go to their output paths [#1116](https://github.com/terrastruct/d2/pull/1116)
|
||||||
|
|
||||||
#### Improvements 🧹
|
#### Improvements 🧹
|
||||||
|
|
||||||
#### Bugfixes ⛑️
|
#### Bugfixes ⛑️
|
||||||
|
|
|
||||||
102
d2cli/main.go
102
d2cli/main.go
|
|
@ -358,6 +358,15 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, rende
|
||||||
return pdf, true, nil
|
return pdf, true, nil
|
||||||
} else {
|
} else {
|
||||||
compileDur := time.Since(start)
|
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)
|
boards, err := render(ctx, ms, compileDur, plugin, renderOpts, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|
@ -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) {
|
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 != "" {
|
if diagram.Name != "" {
|
||||||
ext := filepath.Ext(outputPath)
|
ext := filepath.Ext(outputPath)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func TestCLI_E2E(t *testing.T) {
|
||||||
tca := []struct {
|
tca := []struct {
|
||||||
name string
|
name string
|
||||||
skipCI bool
|
skipCI bool
|
||||||
|
skip bool
|
||||||
run func(t *testing.T, ctx context.Context, dir string, env *xos.Env)
|
run func(t *testing.T, ctx context.Context, dir string, env *xos.Env)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
|
@ -82,6 +83,35 @@ steps: {
|
||||||
assert.Testdata(t, ".svg", svg)
|
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",
|
name: "with-font",
|
||||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||||
|
|
@ -241,6 +271,9 @@ layers: {
|
||||||
if tc.skipCI && os.Getenv("CI") != "" {
|
if tc.skipCI && os.Getenv("CI") != "" {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
if tc.skip {
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
|
ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in a new issue