label works
This commit is contained in:
parent
ce93835777
commit
c9793b9a87
7 changed files with 365 additions and 0 deletions
|
|
@ -423,6 +423,7 @@ func (s *BlockString) value() {}
|
|||
func (a *Array) value() {}
|
||||
func (m *Map) value() {}
|
||||
func (i *Import) value() {}
|
||||
func (i *Substitution) value() {}
|
||||
|
||||
func (n *Null) scalar() {}
|
||||
func (b *Boolean) scalar() {}
|
||||
|
|
@ -901,6 +902,7 @@ type ValueBox struct {
|
|||
Array *Array `json:"array,omitempty"`
|
||||
Map *Map `json:"map,omitempty"`
|
||||
Import *Import `json:"import,omitempty"`
|
||||
Substitution *Substitution `json:"substitution,omitempty"`
|
||||
}
|
||||
|
||||
func (vb ValueBox) Unbox() Value {
|
||||
|
|
@ -925,6 +927,8 @@ func (vb ValueBox) Unbox() Value {
|
|||
return vb.Map
|
||||
case vb.Import != nil:
|
||||
return vb.Import
|
||||
case vb.Substitution != nil:
|
||||
return vb.Substitution
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -953,6 +957,8 @@ func MakeValueBox(v Value) ValueBox {
|
|||
vb.Map = v
|
||||
case *Import:
|
||||
vb.Import = v
|
||||
case *Substitution:
|
||||
vb.Substitution = v
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package d2compiler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -64,6 +65,8 @@ func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) {
|
|||
g := d2graph.NewGraph()
|
||||
g.AST = ast
|
||||
c.compileBoard(g, m)
|
||||
b, _ := json.MarshalIndent(m, "", " ")
|
||||
println("\033[1;31m--- DEBUG:", string(b), "\033[m")
|
||||
if len(c.err.Errors) > 0 {
|
||||
return nil, c.err
|
||||
}
|
||||
|
|
@ -277,6 +280,26 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
|
|||
}
|
||||
}
|
||||
return
|
||||
} else if f.Name == "vars" {
|
||||
if f.Map() != nil {
|
||||
if len(f.Map().Edges) > 0 {
|
||||
c.errorf(f.Map().Edges[0].LastRef().AST(), "vars cannot contain an edge")
|
||||
}
|
||||
// for _, varField := range f.Map().Fields {
|
||||
// if varField.Map() != nil {
|
||||
// c.errorf(varField.LastRef().AST(), "vars must be simple")
|
||||
// }
|
||||
// for _, cf := range classesField.Map().Fields {
|
||||
// if _, ok := d2graph.ReservedKeywords[cf.Name]; !ok {
|
||||
// c.errorf(cf.LastRef().AST(), "%s is an invalid class field, must be reserved keyword", cf.Name)
|
||||
// }
|
||||
// if cf.Name == "class" {
|
||||
// c.errorf(cf.LastRef().AST(), `"class" cannot appear within "classes"`)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return
|
||||
} else if isReserved {
|
||||
c.compileReserved(&obj.Attributes, f)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -2744,6 +2744,7 @@ func TestCompile2(t *testing.T) {
|
|||
t.Run("boards", testBoards)
|
||||
t.Run("seqdiagrams", testSeqDiagrams)
|
||||
t.Run("nulls", testNulls)
|
||||
t.Run("vars", testVars)
|
||||
}
|
||||
|
||||
func testBoards(t *testing.T) {
|
||||
|
|
@ -3168,6 +3169,78 @@ scenarios: {
|
|||
})
|
||||
}
|
||||
|
||||
func testVars(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("basic", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tca := []struct {
|
||||
name string
|
||||
skip bool
|
||||
run func(t *testing.T)
|
||||
}{
|
||||
{
|
||||
name: "label",
|
||||
run: func(t *testing.T) {
|
||||
g := assertCompile(t, `
|
||||
vars: {
|
||||
x: im a var
|
||||
}
|
||||
hi: ${x}
|
||||
`, "")
|
||||
assert.Equal(t, 1, len(g.Objects))
|
||||
assert.Equal(t, "im a var", g.Objects[0].Label.Value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tca {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if tc.skip {
|
||||
t.SkipNow()
|
||||
}
|
||||
tc.run(t)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("errors", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tca := []struct {
|
||||
name string
|
||||
skip bool
|
||||
run func(t *testing.T)
|
||||
}{
|
||||
{
|
||||
name: "missing",
|
||||
run: func(t *testing.T) {
|
||||
assertCompile(t, `
|
||||
vars: {
|
||||
x: hey
|
||||
}
|
||||
hi: ${z}
|
||||
`, "d2/testdata/d2compiler/TestCompile2/vars/errors/missing.d2:5:1: could not resolve variable z")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tca {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if tc.skip {
|
||||
t.SkipNow()
|
||||
}
|
||||
tc.run(t)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func assertCompile(t *testing.T, text string, expErr string) *d2graph.Graph {
|
||||
d2Path := fmt.Sprintf("d2/testdata/d2compiler/%v.d2", t.Name())
|
||||
g, err := d2compiler.Compile(d2Path, strings.NewReader(text), nil)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, error) {
|
|||
|
||||
c.compileMap(m, ast, ast)
|
||||
c.compileClasses(m)
|
||||
c.compileVars(m)
|
||||
c.compileSubstitutions(m)
|
||||
if !c.err.Empty() {
|
||||
return nil, c.err
|
||||
}
|
||||
|
|
@ -96,6 +98,81 @@ func (c *compiler) compileClasses(m *Map) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileSubstitutions(m *Map) {
|
||||
vars := m.GetField("vars")
|
||||
for _, f := range m.Fields {
|
||||
// No substitutions within vars itself
|
||||
if f.Name == "vars" {
|
||||
continue
|
||||
}
|
||||
for _, ref := range f.References {
|
||||
if ref.Context.Key != nil && ref.Context.Key.Value.Substitution != nil {
|
||||
var resolved *Field
|
||||
m := vars
|
||||
for _, p := range ref.Context.Key.Value.Substitution.Path {
|
||||
r := m.Map().GetField(p.Unbox().ScalarString())
|
||||
if r == nil {
|
||||
resolved = nil
|
||||
break
|
||||
}
|
||||
m = r
|
||||
resolved = r
|
||||
}
|
||||
if resolved == nil {
|
||||
c.errorf(ref.Context.Key, "could not resolve variable %s", strings.Join(ref.Context.Key.Value.Substitution.IDA(), "."))
|
||||
} else {
|
||||
// TODO do i need this
|
||||
// ref.Context.Key.Value = d2ast.MakeValueBox(resolved.Primary().Value)
|
||||
|
||||
// TODO maps
|
||||
f.Primary_ = &Scalar{
|
||||
parent: f,
|
||||
Value: resolved.Primary().Value,
|
||||
}
|
||||
}
|
||||
ref.Context.Key.Value.Substitution = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileVars(m *Map) {
|
||||
vars := m.GetField("vars")
|
||||
if vars == nil || vars.Map() == nil {
|
||||
return
|
||||
}
|
||||
|
||||
layersField := m.GetField("layers")
|
||||
if layersField == nil {
|
||||
return
|
||||
}
|
||||
layers := layersField.Map()
|
||||
if layers == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, lf := range layers.Fields {
|
||||
if lf.Map() == nil || lf.Primary() != nil {
|
||||
c.errorf(lf.References[0].Context.Key, "invalid layer")
|
||||
continue
|
||||
}
|
||||
l := lf.Map()
|
||||
lVars := l.GetField("vars")
|
||||
|
||||
if lVars == nil {
|
||||
lVars = vars.Copy(l).(*Field)
|
||||
l.Fields = append(l.Fields, lVars)
|
||||
} else {
|
||||
base := vars.Copy(l).(*Field)
|
||||
OverlayMap(base.Map(), lVars.Map())
|
||||
l.DeleteField("vars")
|
||||
l.Fields = append(l.Fields, base)
|
||||
}
|
||||
|
||||
c.compileVars(l)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) overlay(base *Map, f *Field) {
|
||||
if f.Map() == nil || f.Primary() != nil {
|
||||
c.errorf(f.References[0].Context.Key, "invalid %s", NodeBoardKind(f))
|
||||
|
|
@ -244,6 +321,10 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext)
|
|||
c.compileClasses(f.Map())
|
||||
}
|
||||
}
|
||||
} else if refctx.Key.Value.Substitution != nil {
|
||||
// b, _ := json.MarshalIndent(refctx.Key.Value.Substitution.IDA(), "", " ")
|
||||
// println("\033[1;31m--- DEBUG:", string(b), "\033[m")
|
||||
// println("\033[1;31m--- DEBUG:", "=======what===============", "\033[m")
|
||||
} 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" {
|
||||
|
|
|
|||
|
|
@ -1596,6 +1596,9 @@ func (p *parser) parseValue() d2ast.ValueBox {
|
|||
case '@':
|
||||
box.Import = p.parseImport(false)
|
||||
return box
|
||||
case '$':
|
||||
box.Substitution = p.parseSubstitution(false)
|
||||
return box
|
||||
}
|
||||
|
||||
p.replay(r)
|
||||
|
|
|
|||
168
testdata/d2compiler/TestCompile2/vars/basic/label.exp.json
generated
vendored
Normal file
168
testdata/d2compiler/TestCompile2/vars/basic/label.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
{
|
||||
"graph": {
|
||||
"name": "",
|
||||
"isFolderOnly": false,
|
||||
"ast": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,0:0:0-5:0:34",
|
||||
"nodes": [
|
||||
{
|
||||
"map_key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,1:0:1-3:1:24",
|
||||
"key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,1:0:1-1:4:5",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,1:0:1-1:4:5",
|
||||
"value": [
|
||||
{
|
||||
"string": "vars",
|
||||
"raw_string": "vars"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {},
|
||||
"value": {
|
||||
"map": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,1:6:7-3:1:24",
|
||||
"nodes": [
|
||||
{
|
||||
"map_key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,2:2:11-2:13:22",
|
||||
"key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,2:2:11-2:3:12",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,2:2:11-2:3:12",
|
||||
"value": [
|
||||
{
|
||||
"string": "x",
|
||||
"raw_string": "x"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {},
|
||||
"value": {
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,2:5:14-2:13:22",
|
||||
"value": [
|
||||
{
|
||||
"string": "im a var",
|
||||
"raw_string": "im a var"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"map_key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:0:25-4:8:33",
|
||||
"key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:0:25-4:2:27",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:0:25-4:2:27",
|
||||
"value": [
|
||||
{
|
||||
"string": "hi",
|
||||
"raw_string": "hi"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {},
|
||||
"value": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"root": {
|
||||
"id": "",
|
||||
"id_val": "",
|
||||
"attributes": {
|
||||
"label": {
|
||||
"value": ""
|
||||
},
|
||||
"labelDimensions": {
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"style": {},
|
||||
"near_key": null,
|
||||
"shape": {
|
||||
"value": ""
|
||||
},
|
||||
"direction": {
|
||||
"value": ""
|
||||
},
|
||||
"constraint": null
|
||||
},
|
||||
"zIndex": 0
|
||||
},
|
||||
"edges": null,
|
||||
"objects": [
|
||||
{
|
||||
"id": "hi",
|
||||
"id_val": "hi",
|
||||
"references": [
|
||||
{
|
||||
"key": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:0:25-4:2:27",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:0:25-4:2:27",
|
||||
"value": [
|
||||
{
|
||||
"string": "hi",
|
||||
"raw_string": "hi"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_path_index": 0,
|
||||
"map_key_edge_index": -1
|
||||
}
|
||||
],
|
||||
"attributes": {
|
||||
"label": {
|
||||
"value": "im a var"
|
||||
},
|
||||
"labelDimensions": {
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"style": {},
|
||||
"near_key": null,
|
||||
"shape": {
|
||||
"value": "rectangle"
|
||||
},
|
||||
"direction": {
|
||||
"value": ""
|
||||
},
|
||||
"constraint": null
|
||||
},
|
||||
"zIndex": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"err": null
|
||||
}
|
||||
11
testdata/d2compiler/TestCompile2/vars/errors/missing.exp.json
generated
vendored
Normal file
11
testdata/d2compiler/TestCompile2/vars/errors/missing.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"graph": null,
|
||||
"err": {
|
||||
"errs": [
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile2/vars/errors/missing.d2,4:0:20-4:8:28",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile2/vars/errors/missing.d2:5:1: could not resolve variable z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue