reimplement

This commit is contained in:
Alexander Wang 2023-06-25 23:10:56 -07:00
parent 757f292a20
commit 09d1ec6314
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
8 changed files with 244 additions and 180 deletions

View file

@ -78,6 +78,7 @@ func (c *compiler) compileBoard(g *d2graph.Graph, ir *d2ir.Map) *d2graph.Graph {
ir = ir.Copy(nil).(*d2ir.Map)
// c.preprocessSeqDiagrams(ir)
c.compileMap(g.Root, ir)
c.nullify(g)
if len(c.err.Errors) == 0 {
c.validateKeys(g.Root, ir)
}
@ -244,7 +245,7 @@ func (c *compiler) compileMap(obj *d2graph.Object, m *d2ir.Map) {
}
for _, e := range m.Edges {
c.compileEdge(obj, e)
c.compileEdge(obj, e, m)
}
}
}
@ -303,11 +304,6 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
}
}
if f.Primary() != nil {
if _, ok := f.Primary().Value.(*d2ast.Null); ok {
return
}
}
obj = obj.EnsureChild(d2graphIDA([]string{f.Name}))
if f.Primary() != nil {
@ -708,12 +704,13 @@ func compileStyleFieldInit(attrs *d2graph.Attributes, f *d2ir.Field) {
}
}
func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge, m *d2ir.Map) {
if e.Primary() != nil {
if _, ok := e.Primary().Value.(*d2ast.Null); ok {
return
}
}
edge, err := obj.Connect(d2graphIDA(e.ID.SrcPath), d2graphIDA(e.ID.DstPath), e.ID.SrcArrow, e.ID.DstArrow, "")
if err != nil {
c.errorf(e.References[0].AST(), err.Error())
@ -844,6 +841,14 @@ func (c *compiler) compileArrowheads(edge *d2graph.Edge, f *d2ir.Field) {
}
}
func (c *compiler) nullify(g *d2graph.Graph) {
for _, obj := range g.Objects {
if len(obj.References) > 0 && obj.References[len(obj.References)-1].Nulled() {
g.DeleteObject(obj)
}
}
}
// TODO add more, e.g. C, bash
var ShortToFullLanguageAliases = map[string]string{
"md": "markdown",

View file

@ -3001,6 +3001,39 @@ a
})
}
})
t.Run("implicit", func(t *testing.T) {
t.Parallel()
tca := []struct {
name string
skip bool
run func(t *testing.T)
}{
{
name: "connection",
run: func(t *testing.T) {
g := assertCompile(t, `
x -> y
y: null
`, "")
assert.Equal(t, 1, len(g.Objects))
assert.Equal(t, 0, len(g.Edges))
},
},
}
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 {

View file

@ -73,6 +73,28 @@ func (g *Graph) RootBoard() *Graph {
return g
}
// DeleteObject deletes an object along with all its descendants.
// It also deletes all edges connected to it or a descendant.
func (g *Graph) DeleteObject(obj *Object) {
for i, obj2 := range g.Objects {
if obj == obj2 {
g.Objects = append(g.Objects[:i], g.Objects[i+1:]...)
i--
}
}
obj.Parent.removeChild(obj)
for i, e := range g.Edges {
if e.Src == obj || e.Dst == obj {
g.Edges = append(g.Edges[:i], g.Edges[i+1:]...)
}
}
for _, ch := range obj.ChildrenArray {
g.DeleteObject(ch)
}
}
type LayoutGraph func(context.Context, *Graph) error
// TODO consider having different Scalar types
@ -193,6 +215,10 @@ type Reference struct {
ScopeAST *d2ast.Map `json:"-"`
}
func (r *Reference) Nulled() bool {
return r.MapKey != nil && r.MapKey.Value.Null != nil
}
func (r Reference) MapKeyEdgeDest() bool {
return r.Key == r.MapKey.Edges[r.MapKeyEdgeIndex].Dst
}
@ -785,39 +811,6 @@ func (obj *Object) ensureChildEdge(ida []string) *Object {
return obj
}
// DeleteChild deletes a child from the graph.
// If it has connections or children, those will also be deleted (recursively)
// func (obj *Object) DeleteChild(ida []string) error {
// if len(ida) == 0 {
// return nil
// }
//
// _, is := ReservedKeywordHolders[ida[0]]
// if len(ida) == 1 && !is {
// _, ok := ReservedKeywords[ida[0]]
// if ok {
// return obj
// }
// }
//
// id := ida[0]
// ida = ida[1:]
//
// if id == "_" {
// return obj.Parent.EnsureChild(ida)
// }
//
// child, ok := obj.Children[strings.ToLower(id)]
// if !ok {
// child = obj.newObject(id)
// }
//
// if len(ida) >= 1 {
// return child.EnsureChild(ida)
// }
// return child
// }
// EnsureChild grabs the child by ids or creates it if it does not exist including all
// intermediate nodes.
func (obj *Object) EnsureChild(ida []string) *Object {

View file

@ -156,18 +156,12 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext)
return
}
if f.Primary() != nil {
// null only applies if it's the appearance
if _, ok := f.Primary().Value.(*d2ast.Null); ok {
f.Primary_ = nil
}
}
if refctx.Key.Primary.Unbox() != nil {
f.Primary_ = &Scalar{
parent: f,
Value: refctx.Key.Primary.Unbox(),
}
}
if refctx.Key.Value.Array != nil {
a := &Array{

View file

@ -786,6 +786,20 @@ func (m *Map) GetEdges(eid *EdgeID) []*Edge {
return ea
}
func (m *Map) DeleteEdge(eid *EdgeID) *Edge {
if eid == nil {
return nil
}
for i, e := range m.Edges {
if e.ID.Match(eid) {
m.Edges = append(m.Edges[:i], m.Edges[i+1:]...)
return e
}
}
return nil
}
func (m *Map) CreateEdge(eid *EdgeID, refctx *RefContext) (*Edge, error) {
if ParentEdge(m) != nil {
return nil, d2parser.Errorf(refctx.Edge, "cannot create edge inside edge")

View file

@ -132,138 +132,7 @@
"zIndex": 0
},
"edges": null,
"objects": [
{
"id": "a",
"id_val": "a",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,1:0:1-1:1:2",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,1:0:1-1:1:2",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
},
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,2:1:9-2:2:10",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,2:1:9-2:2:10",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": "a"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "b",
"id_val": "b",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,1:5:6-1:6:7",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,1:5:6-1:6:7",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
},
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,2:6:14-2:7:15",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/basic/edge.d2,2:6:14-2:7:15",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": "b"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
"objects": null
},
"err": null
}

View file

@ -0,0 +1,156 @@
{
"graph": {
"name": "",
"isFolderOnly": false,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,0:0:0-3:0:16",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:0:1-1:6:7",
"edges": [
{
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:0:1-1:6:7",
"src": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:0:1-1:1:2",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:0:1-1:1:2",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
},
"src_arrow": "",
"dst": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:5:6-1:6:7",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:5:6-1:6:7",
"value": [
{
"string": "y",
"raw_string": "y"
}
]
}
}
]
},
"dst_arrow": ">"
}
],
"primary": {},
"value": {}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,2:0:8-2:7:15",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,2:0:8-2:1:9",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,2:0:8-2:1:9",
"value": [
{
"string": "y",
"raw_string": "y"
}
]
}
}
]
},
"primary": {},
"value": {
"null": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,2:3:11-2:7:15"
}
}
}
}
]
},
"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": "x",
"id_val": "x",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:0:1-1:1:2",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/connection.d2,1:0:1-1:1:2",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": "x"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
},
"err": null
}

View file

@ -172,7 +172,7 @@
],
"attributes": {
"label": {
"value": "a"
"value": ""
},
"labelDimensions": {
"width": 0,