@@ -43,8 +43,10 @@ type compiler struct {
43
43
// Used to prevent field globs causing infinite loops.
44
44
globRefContextStack []* RefContext
45
45
// Used to check whether ampersands are allowed in the current map.
46
- mapRefContextStack []* RefContext
47
- lazyGlobBeingApplied bool
46
+ mapRefContextStack []* RefContext
47
+ lazyGlobBeingApplied bool
48
+ markedFieldsForDeletion map [* Map ]map [string ]struct {}
49
+ markedEdgesForDeletion map [* Map ][]* EdgeID
48
50
}
49
51
50
52
type CompileOptions struct {
@@ -65,8 +67,10 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, []string, error) {
65
67
err : & d2parser.ParseError {},
66
68
fs : opts .FS ,
67
69
68
- seenImports : make (map [string ]struct {}),
69
- utf16Pos : opts .UTF16Pos ,
70
+ seenImports : make (map [string ]struct {}),
71
+ utf16Pos : opts .UTF16Pos ,
72
+ markedFieldsForDeletion : make (map [* Map ]map [string ]struct {}),
73
+ markedEdgesForDeletion : make (map [* Map ][]* EdgeID ),
70
74
}
71
75
m := & Map {}
72
76
m .initRoot ()
@@ -81,6 +85,8 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, []string, error) {
81
85
c .compileMap (m , ast , ast )
82
86
c .compileSubstitutions (m , nil )
83
87
c .overlayClasses (m )
88
+ c .processMarkedDeletions (m )
89
+
84
90
if ! c .err .Empty () {
85
91
return nil , nil , c .err
86
92
}
@@ -862,12 +868,17 @@ func (c *compiler) _compileField(f *Field, refctx *RefContext) {
862
868
// For vars, if we delete the field, it may just resolve to an outer scope var of the same name
863
869
// Instead we keep it around, so that resolveSubstitutions can find it
864
870
if ! IsVar (ParentMap (f )) {
865
- ParentMap (f ). DeleteField ( f .Name .ScalarString ())
871
+ c . markFieldForDeletion ( ParentMap (f ), f .Name .ScalarString ())
866
872
}
867
873
}
868
874
return
869
875
}
870
876
877
+ if len (refctx .Key .Edges ) == 0 && (refctx .Key .Primary .NotNull != nil || refctx .Key .Value .NotNull != nil ) {
878
+ c .unmarkFieldForDeletion (ParentMap (f ), f .Name .ScalarString ())
879
+ return
880
+ }
881
+
871
882
if refctx .Key .Primary .Unbox () != nil {
872
883
if c .ignoreLazyGlob (f ) {
873
884
return
@@ -1146,10 +1157,14 @@ func (c *compiler) _compileEdges(refctx *RefContext) {
1146
1157
for i , eid := range eida {
1147
1158
if ! eid .Glob && (refctx .Key .Primary .Null != nil || refctx .Key .Value .Null != nil ) {
1148
1159
if ! c .lazyGlobBeingApplied {
1149
- refctx .ScopeMap . DeleteEdge ( eid )
1160
+ c . markEdgeForDeletion ( refctx .ScopeMap , eid )
1150
1161
}
1151
1162
continue
1152
1163
}
1164
+ if ! eid .Glob && (refctx .Key .Primary .NotNull != nil || refctx .Key .Value .NotNull != nil ) {
1165
+ c .unmarkEdgeForDeletion (refctx .ScopeMap , eid )
1166
+ continue
1167
+ }
1153
1168
1154
1169
refctx = refctx .Copy ()
1155
1170
refctx .Edge = refctx .Key .Edges [i ]
@@ -1295,3 +1310,51 @@ func (c *compiler) compileArray(dst *Array, a *d2ast.Array, scopeAST *d2ast.Map)
1295
1310
dst .Values = append (dst .Values , irv )
1296
1311
}
1297
1312
}
1313
+
1314
+ func (c * compiler ) markFieldForDeletion (parent * Map , key string ) {
1315
+ if c .markedFieldsForDeletion [parent ] == nil {
1316
+ c .markedFieldsForDeletion [parent ] = make (map [string ]struct {})
1317
+ }
1318
+ c.markedFieldsForDeletion [parent ][key ] = struct {}{}
1319
+ }
1320
+
1321
+ func (c * compiler ) unmarkFieldForDeletion (parent * Map , key string ) {
1322
+ if c .markedFieldsForDeletion [parent ] != nil {
1323
+ delete (c .markedFieldsForDeletion [parent ], key )
1324
+ }
1325
+ }
1326
+
1327
+ func (c * compiler ) markEdgeForDeletion (parent * Map , eid * EdgeID ) {
1328
+ c .markedEdgesForDeletion [parent ] = append (c .markedEdgesForDeletion [parent ], eid .Copy ())
1329
+ }
1330
+
1331
+ func (c * compiler ) unmarkEdgeForDeletion (parent * Map , eid * EdgeID ) {
1332
+ edges := c .markedEdgesForDeletion [parent ]
1333
+ for i , e := range edges {
1334
+ if e .Match (eid ) {
1335
+ // Remove this edge from the slice
1336
+ c .markedEdgesForDeletion [parent ] = append (edges [:i ], edges [i + 1 :]... )
1337
+ break
1338
+ }
1339
+ }
1340
+ }
1341
+
1342
+ func (c * compiler ) processMarkedDeletions (m * Map ) {
1343
+ // Process field deletions
1344
+ for parent , keys := range c .markedFieldsForDeletion {
1345
+ for key := range keys {
1346
+ parent .DeleteField (key )
1347
+ }
1348
+ }
1349
+
1350
+ // Process edge deletions
1351
+ for parent , edges := range c .markedEdgesForDeletion {
1352
+ for _ , eid := range edges {
1353
+ parent .DeleteEdge (eid )
1354
+ }
1355
+ }
1356
+
1357
+ // Clear the tracking maps
1358
+ c .markedFieldsForDeletion = make (map [* Map ]map [string ]struct {})
1359
+ c .markedEdgesForDeletion = make (map [* Map ][]* EdgeID )
1360
+ }
0 commit comments