diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go
index 5928cd164..3a5b83253 100644
--- a/d2compiler/compile_test.go
+++ b/d2compiler/compile_test.go
@@ -2339,6 +2339,20 @@ ok: {
tassert.Equal(t, "null", g.Objects[0].IDVal)
},
},
+ {
+ name: "no-lazy-null",
+
+ text: `a
+a -> b
+c.d
+**: null
+
+g
+`,
+ assertions: func(t *testing.T, g *d2graph.Graph) {
+ tassert.Equal(t, 1, len(g.Objects))
+ },
+ },
{
name: "sql-regression",
diff --git a/d2ir/compile.go b/d2ir/compile.go
index f7436dcb1..3ae17822f 100644
--- a/d2ir/compile.go
+++ b/d2ir/compile.go
@@ -43,8 +43,10 @@ type compiler struct {
// Used to prevent field globs causing infinite loops.
globRefContextStack []*RefContext
// Used to check whether ampersands are allowed in the current map.
- mapRefContextStack []*RefContext
- lazyGlobBeingApplied bool
+ mapRefContextStack []*RefContext
+ lazyGlobBeingApplied bool
+ markedFieldsForDeletion map[*Map]map[string]struct{}
+ markedEdgesForDeletion map[*Map][]*EdgeID
}
type CompileOptions struct {
@@ -65,8 +67,10 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, []string, error) {
err: &d2parser.ParseError{},
fs: opts.FS,
- seenImports: make(map[string]struct{}),
- utf16Pos: opts.UTF16Pos,
+ seenImports: make(map[string]struct{}),
+ utf16Pos: opts.UTF16Pos,
+ markedFieldsForDeletion: make(map[*Map]map[string]struct{}),
+ markedEdgesForDeletion: make(map[*Map][]*EdgeID),
}
m := &Map{}
m.initRoot()
@@ -81,6 +85,8 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, []string, error) {
c.compileMap(m, ast, ast)
c.compileSubstitutions(m, nil)
c.overlayClasses(m)
+ c.processMarkedDeletions(m)
+
if !c.err.Empty() {
return nil, nil, c.err
}
@@ -862,12 +868,17 @@ func (c *compiler) _compileField(f *Field, refctx *RefContext) {
// For vars, if we delete the field, it may just resolve to an outer scope var of the same name
// Instead we keep it around, so that resolveSubstitutions can find it
if !IsVar(ParentMap(f)) {
- ParentMap(f).DeleteField(f.Name.ScalarString())
+ c.markFieldForDeletion(ParentMap(f), f.Name.ScalarString())
}
}
return
}
+ if len(refctx.Key.Edges) == 0 && (refctx.Key.Primary.NotNull != nil || refctx.Key.Value.NotNull != nil) {
+ c.unmarkFieldForDeletion(ParentMap(f), f.Name.ScalarString())
+ return
+ }
+
if refctx.Key.Primary.Unbox() != nil {
if c.ignoreLazyGlob(f) {
return
@@ -1146,10 +1157,14 @@ func (c *compiler) _compileEdges(refctx *RefContext) {
for i, eid := range eida {
if !eid.Glob && (refctx.Key.Primary.Null != nil || refctx.Key.Value.Null != nil) {
if !c.lazyGlobBeingApplied {
- refctx.ScopeMap.DeleteEdge(eid)
+ c.markEdgeForDeletion(refctx.ScopeMap, eid)
}
continue
}
+ if !eid.Glob && (refctx.Key.Primary.NotNull != nil || refctx.Key.Value.NotNull != nil) {
+ c.unmarkEdgeForDeletion(refctx.ScopeMap, eid)
+ continue
+ }
refctx = refctx.Copy()
refctx.Edge = refctx.Key.Edges[i]
@@ -1295,3 +1310,51 @@ func (c *compiler) compileArray(dst *Array, a *d2ast.Array, scopeAST *d2ast.Map)
dst.Values = append(dst.Values, irv)
}
}
+
+func (c *compiler) markFieldForDeletion(parent *Map, key string) {
+ if c.markedFieldsForDeletion[parent] == nil {
+ c.markedFieldsForDeletion[parent] = make(map[string]struct{})
+ }
+ c.markedFieldsForDeletion[parent][key] = struct{}{}
+}
+
+func (c *compiler) unmarkFieldForDeletion(parent *Map, key string) {
+ if c.markedFieldsForDeletion[parent] != nil {
+ delete(c.markedFieldsForDeletion[parent], key)
+ }
+}
+
+func (c *compiler) markEdgeForDeletion(parent *Map, eid *EdgeID) {
+ c.markedEdgesForDeletion[parent] = append(c.markedEdgesForDeletion[parent], eid.Copy())
+}
+
+func (c *compiler) unmarkEdgeForDeletion(parent *Map, eid *EdgeID) {
+ edges := c.markedEdgesForDeletion[parent]
+ for i, e := range edges {
+ if e.Match(eid) {
+ // Remove this edge from the slice
+ c.markedEdgesForDeletion[parent] = append(edges[:i], edges[i+1:]...)
+ break
+ }
+ }
+}
+
+func (c *compiler) processMarkedDeletions(m *Map) {
+ // Process field deletions
+ for parent, keys := range c.markedFieldsForDeletion {
+ for key := range keys {
+ parent.DeleteField(key)
+ }
+ }
+
+ // Process edge deletions
+ for parent, edges := range c.markedEdgesForDeletion {
+ for _, eid := range edges {
+ parent.DeleteEdge(eid)
+ }
+ }
+
+ // Clear the tracking maps
+ c.markedFieldsForDeletion = make(map[*Map]map[string]struct{})
+ c.markedEdgesForDeletion = make(map[*Map][]*EdgeID)
+}
diff --git a/e2etests/testdata/txtar/model-nulling/dagre/board.exp.json b/e2etests/testdata/txtar/model-nulling/dagre/board.exp.json
index d36039885..163137c4c 100644
--- a/e2etests/testdata/txtar/model-nulling/dagre/board.exp.json
+++ b/e2etests/testdata/txtar/model-nulling/dagre/board.exp.json
@@ -11,225 +11,57 @@
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
- {
- "id": "hello",
- "type": "rectangle",
- "pos": {
- "x": 0,
- "y": 67
- },
- "width": 80,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B6",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "hello",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 35,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 1
- },
- {
- "id": "yes",
- "type": "rectangle",
- "pos": {
- "x": 130,
- "y": 37
- },
- "width": 123,
- "height": 126,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B4",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "yes",
- "fontSize": 28,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": false,
- "underline": false,
- "labelWidth": 38,
- "labelHeight": 36,
- "labelPosition": "OUTSIDE_TOP_CENTER",
- "zIndex": 0,
- "level": 1
- },
- {
- "id": "yes.ok",
- "type": "rectangle",
- "pos": {
- "x": 160,
- "y": 67
- },
- "width": 63,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B5",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "ok",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 18,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 2
- },
- {
- "id": "a",
- "type": "rectangle",
- "pos": {
- "x": 463,
- "y": 67
- },
- "width": 53,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B6",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "a",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 8,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 1
- },
- {
- "id": "b",
- "type": "rectangle",
- "pos": {
- "x": 463,
- "y": 300
- },
- "width": 53,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B6",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "b",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 8,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 1
- },
{
"id": "user",
"type": "rectangle",
"pos": {
- "x": 303,
- "y": 50
+ "x": 0,
+ "y": 0
},
- "width": 100,
- "height": 100,
+ "width": 77,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "blue",
+ "stroke": "B1",
+ "animated": false,
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "user",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 32,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "softwareSystem",
+ "type": "rectangle",
+ "pos": {
+ "x": 137,
+ "y": 0
+ },
+ "width": 160,
+ "height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -249,7 +81,7 @@
"fields": null,
"methods": null,
"columns": null,
- "label": "",
+ "label": "softwareSystem",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
@@ -257,62 +89,56 @@
"italic": false,
"bold": true,
"underline": false,
- "labelWidth": 0,
- "labelHeight": 0,
+ "labelWidth": 115,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "externalSystem",
+ "type": "rectangle",
+ "pos": {
+ "x": 357,
+ "y": 0
+ },
+ "width": 157,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "stroke": "B1",
+ "animated": false,
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "externalSystem",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 112,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
}
],
- "connections": [
- {
- "id": "(a -> b)[0]",
- "src": "a",
- "srcArrow": "none",
- "dst": "b",
- "dstArrow": "triangle",
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "stroke": "B1",
- "borderRadius": 10,
- "label": "",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N2",
- "italic": true,
- "bold": false,
- "underline": false,
- "labelWidth": 0,
- "labelHeight": 0,
- "labelPosition": "",
- "labelPercentage": 0,
- "link": "",
- "route": [
- {
- "x": 489.5,
- "y": 133
- },
- {
- "x": 489.5,
- "y": 186.60000610351562
- },
- {
- "x": 489.5,
- "y": 260
- },
- {
- "x": 489.5,
- "y": 300
- }
- ],
- "isCurve": true,
- "animated": false,
- "tooltip": "",
- "icon": null,
- "zIndex": 0
- }
- ],
+ "connections": [],
"root": {
"id": "",
"type": "",
diff --git a/e2etests/testdata/txtar/model-nulling/dagre/sketch.exp.svg b/e2etests/testdata/txtar/model-nulling/dagre/sketch.exp.svg
index 275e0b82f..6497c3fbd 100644
--- a/e2etests/testdata/txtar/model-nulling/dagre/sketch.exp.svg
+++ b/e2etests/testdata/txtar/model-nulling/dagre/sketch.exp.svg
@@ -1,17 +1,10 @@
-
\ No newline at end of file
diff --git a/e2etests/testdata/txtar/model-nulling/elk/board.exp.json b/e2etests/testdata/txtar/model-nulling/elk/board.exp.json
index 1175c326a..6c8f563a2 100644
--- a/e2etests/testdata/txtar/model-nulling/elk/board.exp.json
+++ b/e2etests/testdata/txtar/model-nulling/elk/board.exp.json
@@ -11,225 +11,57 @@
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
- {
- "id": "hello",
- "type": "rectangle",
- "pos": {
- "x": 12,
- "y": 62
- },
- "width": 80,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B6",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "hello",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 35,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 1
- },
- {
- "id": "yes",
- "type": "rectangle",
- "pos": {
- "x": 112,
- "y": 12
- },
- "width": 163,
- "height": 166,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B4",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "yes",
- "fontSize": 28,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": false,
- "underline": false,
- "labelWidth": 38,
- "labelHeight": 36,
- "labelPosition": "INSIDE_TOP_CENTER",
- "zIndex": 0,
- "level": 1
- },
- {
- "id": "yes.ok",
- "type": "rectangle",
- "pos": {
- "x": 162,
- "y": 62
- },
- "width": 63,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B5",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "ok",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 18,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 2
- },
- {
- "id": "a",
- "type": "rectangle",
- "pos": {
- "x": 295,
- "y": 112
- },
- "width": 53,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B6",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "a",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 8,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 1
- },
- {
- "id": "b",
- "type": "rectangle",
- "pos": {
- "x": 295,
- "y": 248
- },
- "width": 53,
- "height": 66,
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "borderRadius": 0,
- "fill": "B6",
- "stroke": "B1",
- "animated": false,
- "shadow": false,
- "3d": false,
- "multiple": false,
- "double-border": false,
- "tooltip": "",
- "link": "",
- "icon": null,
- "iconPosition": "",
- "blend": false,
- "fields": null,
- "methods": null,
- "columns": null,
- "label": "b",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N1",
- "italic": false,
- "bold": true,
- "underline": false,
- "labelWidth": 8,
- "labelHeight": 21,
- "labelPosition": "INSIDE_MIDDLE_CENTER",
- "zIndex": 0,
- "level": 1
- },
{
"id": "user",
"type": "rectangle",
"pos": {
- "x": 368,
- "y": 45
+ "x": 12,
+ "y": 12
},
- "width": 100,
- "height": 100,
+ "width": 77,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "blue",
+ "stroke": "B1",
+ "animated": false,
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "user",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 32,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "softwareSystem",
+ "type": "rectangle",
+ "pos": {
+ "x": 109,
+ "y": 12
+ },
+ "width": 160,
+ "height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -249,7 +81,7 @@
"fields": null,
"methods": null,
"columns": null,
- "label": "",
+ "label": "softwareSystem",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
@@ -257,53 +89,56 @@
"italic": false,
"bold": true,
"underline": false,
- "labelWidth": 0,
- "labelHeight": 0,
+ "labelWidth": 115,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "externalSystem",
+ "type": "rectangle",
+ "pos": {
+ "x": 289,
+ "y": 12
+ },
+ "width": 157,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "stroke": "B1",
+ "animated": false,
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "externalSystem",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 112,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
}
],
- "connections": [
- {
- "id": "(a -> b)[0]",
- "src": "a",
- "srcArrow": "none",
- "dst": "b",
- "dstArrow": "triangle",
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "stroke": "B1",
- "borderRadius": 10,
- "label": "",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "N2",
- "italic": true,
- "bold": false,
- "underline": false,
- "labelWidth": 0,
- "labelHeight": 0,
- "labelPosition": "",
- "labelPercentage": 0,
- "link": "",
- "route": [
- {
- "x": 321.5,
- "y": 178
- },
- {
- "x": 321.5,
- "y": 248
- }
- ],
- "animated": false,
- "tooltip": "",
- "icon": null,
- "zIndex": 0
- }
- ],
+ "connections": [],
"root": {
"id": "",
"type": "",
diff --git a/e2etests/testdata/txtar/model-nulling/elk/sketch.exp.svg b/e2etests/testdata/txtar/model-nulling/elk/sketch.exp.svg
index ca9dadd55..589759fb5 100644
--- a/e2etests/testdata/txtar/model-nulling/elk/sketch.exp.svg
+++ b/e2etests/testdata/txtar/model-nulling/elk/sketch.exp.svg
@@ -1,17 +1,10 @@
-helloyesabok
-
-
-
-
-
-
+ .d2-3796386236 .fill-N1{fill:#0A0F25;}
+ .d2-3796386236 .fill-N2{fill:#676C7E;}
+ .d2-3796386236 .fill-N3{fill:#9499AB;}
+ .d2-3796386236 .fill-N4{fill:#CFD2DD;}
+ .d2-3796386236 .fill-N5{fill:#DEE1EB;}
+ .d2-3796386236 .fill-N6{fill:#EEF1F8;}
+ .d2-3796386236 .fill-N7{fill:#FFFFFF;}
+ .d2-3796386236 .fill-B1{fill:#0D32B2;}
+ .d2-3796386236 .fill-B2{fill:#0D32B2;}
+ .d2-3796386236 .fill-B3{fill:#E3E9FD;}
+ .d2-3796386236 .fill-B4{fill:#E3E9FD;}
+ .d2-3796386236 .fill-B5{fill:#EDF0FD;}
+ .d2-3796386236 .fill-B6{fill:#F7F8FE;}
+ .d2-3796386236 .fill-AA2{fill:#4A6FF3;}
+ .d2-3796386236 .fill-AA4{fill:#EDF0FD;}
+ .d2-3796386236 .fill-AA5{fill:#F7F8FE;}
+ .d2-3796386236 .fill-AB4{fill:#EDF0FD;}
+ .d2-3796386236 .fill-AB5{fill:#F7F8FE;}
+ .d2-3796386236 .stroke-N1{stroke:#0A0F25;}
+ .d2-3796386236 .stroke-N2{stroke:#676C7E;}
+ .d2-3796386236 .stroke-N3{stroke:#9499AB;}
+ .d2-3796386236 .stroke-N4{stroke:#CFD2DD;}
+ .d2-3796386236 .stroke-N5{stroke:#DEE1EB;}
+ .d2-3796386236 .stroke-N6{stroke:#EEF1F8;}
+ .d2-3796386236 .stroke-N7{stroke:#FFFFFF;}
+ .d2-3796386236 .stroke-B1{stroke:#0D32B2;}
+ .d2-3796386236 .stroke-B2{stroke:#0D32B2;}
+ .d2-3796386236 .stroke-B3{stroke:#E3E9FD;}
+ .d2-3796386236 .stroke-B4{stroke:#E3E9FD;}
+ .d2-3796386236 .stroke-B5{stroke:#EDF0FD;}
+ .d2-3796386236 .stroke-B6{stroke:#F7F8FE;}
+ .d2-3796386236 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-3796386236 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-3796386236 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-3796386236 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-3796386236 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-3796386236 .background-color-N1{background-color:#0A0F25;}
+ .d2-3796386236 .background-color-N2{background-color:#676C7E;}
+ .d2-3796386236 .background-color-N3{background-color:#9499AB;}
+ .d2-3796386236 .background-color-N4{background-color:#CFD2DD;}
+ .d2-3796386236 .background-color-N5{background-color:#DEE1EB;}
+ .d2-3796386236 .background-color-N6{background-color:#EEF1F8;}
+ .d2-3796386236 .background-color-N7{background-color:#FFFFFF;}
+ .d2-3796386236 .background-color-B1{background-color:#0D32B2;}
+ .d2-3796386236 .background-color-B2{background-color:#0D32B2;}
+ .d2-3796386236 .background-color-B3{background-color:#E3E9FD;}
+ .d2-3796386236 .background-color-B4{background-color:#E3E9FD;}
+ .d2-3796386236 .background-color-B5{background-color:#EDF0FD;}
+ .d2-3796386236 .background-color-B6{background-color:#F7F8FE;}
+ .d2-3796386236 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-3796386236 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-3796386236 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-3796386236 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-3796386236 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-3796386236 .color-N1{color:#0A0F25;}
+ .d2-3796386236 .color-N2{color:#676C7E;}
+ .d2-3796386236 .color-N3{color:#9499AB;}
+ .d2-3796386236 .color-N4{color:#CFD2DD;}
+ .d2-3796386236 .color-N5{color:#DEE1EB;}
+ .d2-3796386236 .color-N6{color:#EEF1F8;}
+ .d2-3796386236 .color-N7{color:#FFFFFF;}
+ .d2-3796386236 .color-B1{color:#0D32B2;}
+ .d2-3796386236 .color-B2{color:#0D32B2;}
+ .d2-3796386236 .color-B3{color:#E3E9FD;}
+ .d2-3796386236 .color-B4{color:#E3E9FD;}
+ .d2-3796386236 .color-B5{color:#EDF0FD;}
+ .d2-3796386236 .color-B6{color:#F7F8FE;}
+ .d2-3796386236 .color-AA2{color:#4A6FF3;}
+ .d2-3796386236 .color-AA4{color:#EDF0FD;}
+ .d2-3796386236 .color-AA5{color:#F7F8FE;}
+ .d2-3796386236 .color-AB4{color:#EDF0FD;}
+ .d2-3796386236 .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-d2-3796386236);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3796386236);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3796386236);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3796386236);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3796386236);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3796386236);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3796386236);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3796386236);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>usersoftwareSystemexternalSystem
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/txtar.txt b/e2etests/txtar.txt
index a8fd32c81..3cf1566f3 100644
--- a/e2etests/txtar.txt
+++ b/e2etests/txtar.txt
@@ -797,10 +797,4 @@ softwareSystem -> externalSystem
**: null
(** -> **)[*]: null
-hello
-yes: {
- ok
-}
-a -> b
-
-user: !null
+*: !null
diff --git a/testdata/d2compiler/TestCompile/no-lazy-null.exp.json b/testdata/d2compiler/TestCompile/no-lazy-null.exp.json
new file mode 100644
index 000000000..38f609a38
--- /dev/null
+++ b/testdata/d2compiler/TestCompile/no-lazy-null.exp.json
@@ -0,0 +1,241 @@
+{
+ "graph": {
+ "name": "",
+ "isFolderOnly": false,
+ "ast": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,0:0:0-6:0:25",
+ "nodes": [
+ {
+ "map_key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,0:0:0-0:1:1",
+ "key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,0:0:0-0:1:1",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,0:0:0-0:1:1",
+ "value": [
+ {
+ "string": "a",
+ "raw_string": "a"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "primary": {},
+ "value": {}
+ }
+ },
+ {
+ "map_key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,1:0:2-1:6:8",
+ "edges": [
+ {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,1:0:2-1:6:8",
+ "src": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,1:0:2-1:1:3",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,1:0:2-1:1:3",
+ "value": [
+ {
+ "string": "a",
+ "raw_string": "a"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "src_arrow": "",
+ "dst": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,1:5:7-1:6:8",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,1:5:7-1:6:8",
+ "value": [
+ {
+ "string": "b",
+ "raw_string": "b"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "dst_arrow": ">"
+ }
+ ],
+ "primary": {},
+ "value": {}
+ }
+ },
+ {
+ "map_key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,2:0:9-2:3:12",
+ "key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,2:0:9-2:3:12",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,2:0:9-2:1:10",
+ "value": [
+ {
+ "string": "c",
+ "raw_string": "c"
+ }
+ ]
+ }
+ },
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,2:2:11-2:3:12",
+ "value": [
+ {
+ "string": "d",
+ "raw_string": "d"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "primary": {},
+ "value": {}
+ }
+ },
+ {
+ "map_key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,3:0:13-3:8:21",
+ "key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,3:0:13-3:2:15",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,3:0:13-3:2:15",
+ "value": [
+ {
+ "string": "**",
+ "raw_string": "**"
+ }
+ ],
+ "pattern": [
+ "*",
+ "",
+ "*"
+ ]
+ }
+ }
+ ]
+ },
+ "primary": {},
+ "value": {
+ "null": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,3:4:17-3:8:21"
+ }
+ }
+ }
+ },
+ {
+ "map_key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,5:0:23-5:1:24",
+ "key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,5:0:23-5:1:24",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,5:0:23-5:1:24",
+ "value": [
+ {
+ "string": "g",
+ "raw_string": "g"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "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": "g",
+ "id_val": "g",
+ "references": [
+ {
+ "key": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,5:0:23-5:1:24",
+ "path": [
+ {
+ "unquoted_string": {
+ "range": "d2/testdata/d2compiler/TestCompile/no-lazy-null.d2,5:0:23-5:1:24",
+ "value": [
+ {
+ "string": "g",
+ "raw_string": "g"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "key_path_index": 0,
+ "map_key_edge_index": -1
+ }
+ ],
+ "attributes": {
+ "label": {
+ "value": "g"
+ },
+ "labelDimensions": {
+ "width": 0,
+ "height": 0
+ },
+ "style": {},
+ "near_key": null,
+ "shape": {
+ "value": "rectangle"
+ },
+ "direction": {
+ "value": ""
+ },
+ "constraint": null
+ },
+ "zIndex": 0
+ }
+ ]
+ },
+ "err": null
+}
diff --git a/testdata/d2compiler/TestCompile2/nulls/implicit/no-delete-connection.exp.json b/testdata/d2compiler/TestCompile2/nulls/implicit/no-delete-connection.exp.json
index c0b0e4fc1..d787ba546 100644
--- a/testdata/d2compiler/TestCompile2/nulls/implicit/no-delete-connection.exp.json
+++ b/testdata/d2compiler/TestCompile2/nulls/implicit/no-delete-connection.exp.json
@@ -103,38 +103,7 @@
},
"zIndex": 0
},
- "edges": [
- {
- "index": 0,
- "isCurve": false,
- "src_arrow": false,
- "dst_arrow": true,
- "references": [
- {
- "map_key_edge_index": 0
- }
- ],
- "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",
@@ -180,51 +149,6 @@
"constraint": null
},
"zIndex": 0
- },
- {
- "id": "y",
- "id_val": "y",
- "references": [
- {
- "key": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/no-delete-connection.d2,2:5:14-2:6:15",
- "path": [
- {
- "unquoted_string": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/no-delete-connection.d2,2:5:14-2:6:15",
- "value": [
- {
- "string": "y",
- "raw_string": "y"
- }
- ]
- }
- }
- ]
- },
- "key_path_index": 0,
- "map_key_edge_index": 0
- }
- ],
- "attributes": {
- "label": {
- "value": "y"
- },
- "labelDimensions": {
- "width": 0,
- "height": 0
- },
- "style": {},
- "near_key": null,
- "shape": {
- "value": "rectangle"
- },
- "direction": {
- "value": ""
- },
- "constraint": null
- },
- "zIndex": 0
}
]
},
diff --git a/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.exp.json b/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.exp.json
index 92f2e464a..45dfdd32d 100644
--- a/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.exp.json
+++ b/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.exp.json
@@ -1,7 +1,7 @@
{
"graph": {
"name": "",
- "isFolderOnly": false,
+ "isFolderOnly": true,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.d2,0:0:0-4:0:32",
"nodes": [
@@ -132,53 +132,7 @@
"zIndex": 0
},
"edges": null,
- "objects": [
- {
- "id": "a",
- "id_val": "a",
- "references": [
- {
- "key": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.d2,3:0:30-3:1:31",
- "path": [
- {
- "unquoted_string": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/attribute-reset.d2,3:0:30-3:1:31",
- "value": [
- {
- "string": "a",
- "raw_string": "a"
- }
- ]
- }
- }
- ]
- },
- "key_path_index": 0,
- "map_key_edge_index": -1
- }
- ],
- "attributes": {
- "label": {
- "value": "a"
- },
- "labelDimensions": {
- "width": 0,
- "height": 0
- },
- "style": {},
- "near_key": null,
- "shape": {
- "value": "rectangle"
- },
- "direction": {
- "value": ""
- },
- "constraint": null
- },
- "zIndex": 0
- }
- ]
+ "objects": null
},
"err": null
}
diff --git a/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.exp.json b/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.exp.json
index 6af8f1845..8d39010c9 100644
--- a/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.exp.json
+++ b/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.exp.json
@@ -277,62 +277,6 @@
"constraint": null
},
"zIndex": 0
- },
- {
- "id": "b",
- "id_val": "b",
- "references": [
- {
- "key": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.d2,3:0:17-3:3:20",
- "path": [
- {
- "unquoted_string": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.d2,3:0:17-3:1:18",
- "value": [
- {
- "string": "a",
- "raw_string": "a"
- }
- ]
- }
- },
- {
- "unquoted_string": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/children-reset.d2,3:2:19-3:3:20",
- "value": [
- {
- "string": "b",
- "raw_string": "b"
- }
- ]
- }
- }
- ]
- },
- "key_path_index": 1,
- "map_key_edge_index": -1
- }
- ],
- "attributes": {
- "label": {
- "value": "b"
- },
- "labelDimensions": {
- "width": 0,
- "height": 0
- },
- "style": {},
- "near_key": null,
- "shape": {
- "value": "rectangle"
- },
- "direction": {
- "value": ""
- },
- "constraint": null
- },
- "zIndex": 0
}
]
},
diff --git a/testdata/d2compiler/TestCompile2/nulls/reappear/edge-reset.exp.json b/testdata/d2compiler/TestCompile2/nulls/reappear/edge-reset.exp.json
index d6e3860e1..3d5dfed15 100644
--- a/testdata/d2compiler/TestCompile2/nulls/reappear/edge-reset.exp.json
+++ b/testdata/d2compiler/TestCompile2/nulls/reappear/edge-reset.exp.json
@@ -172,51 +172,6 @@
"constraint": null
},
"zIndex": 0
- },
- {
- "id": "a",
- "id_val": "a",
- "references": [
- {
- "key": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/edge-reset.d2,3:0:16-3:1:17",
- "path": [
- {
- "unquoted_string": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/edge-reset.d2,3:0:16-3:1:17",
- "value": [
- {
- "string": "a",
- "raw_string": "a"
- }
- ]
- }
- }
- ]
- },
- "key_path_index": 0,
- "map_key_edge_index": -1
- }
- ],
- "attributes": {
- "label": {
- "value": "a"
- },
- "labelDimensions": {
- "width": 0,
- "height": 0
- },
- "style": {},
- "near_key": null,
- "shape": {
- "value": "rectangle"
- },
- "direction": {
- "value": ""
- },
- "constraint": null
- },
- "zIndex": 0
}
]
},
diff --git a/testdata/d2compiler/TestCompile2/nulls/reappear/shape.exp.json b/testdata/d2compiler/TestCompile2/nulls/reappear/shape.exp.json
index 744b757f3..d4773e351 100644
--- a/testdata/d2compiler/TestCompile2/nulls/reappear/shape.exp.json
+++ b/testdata/d2compiler/TestCompile2/nulls/reappear/shape.exp.json
@@ -1,7 +1,7 @@
{
"graph": {
"name": "",
- "isFolderOnly": false,
+ "isFolderOnly": true,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/shape.d2,0:0:0-4:0:13",
"nodes": [
@@ -104,53 +104,7 @@
"zIndex": 0
},
"edges": null,
- "objects": [
- {
- "id": "a",
- "id_val": "a",
- "references": [
- {
- "key": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/shape.d2,3:0:11-3:1:12",
- "path": [
- {
- "unquoted_string": {
- "range": "d2/testdata/d2compiler/TestCompile2/nulls/reappear/shape.d2,3:0:11-3:1:12",
- "value": [
- {
- "string": "a",
- "raw_string": "a"
- }
- ]
- }
- }
- ]
- },
- "key_path_index": 0,
- "map_key_edge_index": -1
- }
- ],
- "attributes": {
- "label": {
- "value": "a"
- },
- "labelDimensions": {
- "width": 0,
- "height": 0
- },
- "style": {},
- "near_key": null,
- "shape": {
- "value": "rectangle"
- },
- "direction": {
- "value": ""
- },
- "constraint": null
- },
- "zIndex": 0
- }
- ]
+ "objects": null
},
"err": null
}