From 86549a0b5654efff02673f75b428450ac2a82d1a Mon Sep 17 00:00:00 2001
From: Alexander Wang <alex@terrastruct.com>
Date: Thu, 14 Mar 2024 09:50:11 -0700
Subject: [PATCH] d2oracle: fix set with classes setting labels

---
 d2oracle/edit.go                              |  13 +
 d2oracle/edit_test.go                         |  77 ++++
 .../TestSet/class-with-label.exp.json         | 324 +++++++++++++++
 .../TestSet/edge-class-with-label.exp.json    | 377 ++++++++++++++++++
 .../d2oracle/TestSet/glob-with-label.exp.json | 245 ++++++++++++
 .../d2oracle/TestSet/var-with-label.exp.json  | 238 +++++++++++
 6 files changed, 1274 insertions(+)
 create mode 100644 testdata/d2oracle/TestSet/class-with-label.exp.json
 create mode 100644 testdata/d2oracle/TestSet/edge-class-with-label.exp.json
 create mode 100644 testdata/d2oracle/TestSet/glob-with-label.exp.json
 create mode 100644 testdata/d2oracle/TestSet/var-with-label.exp.json

diff --git a/d2oracle/edit.go b/d2oracle/edit.go
index 6d3bea97f6..3f1a84be03 100644
--- a/d2oracle/edit.go
+++ b/d2oracle/edit.go
@@ -429,6 +429,19 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
 					break
 				}
 			}
+		} else {
+			// Even if not imported or different board, a label can be not writeable if it's in a class or var or glob
+			// In those cases, the label is not a direct object reference
+			found := false
+			for _, ref := range obj.References {
+				if ref.MapKey == obj.Label.MapKey {
+					found = true
+					break
+				}
+			}
+			if !found {
+				writeableLabelMK = false
+			}
 		}
 		var m *d2ast.Map
 		if objK != nil {
diff --git a/d2oracle/edit_test.go b/d2oracle/edit_test.go
index a5743234d9..036affcfb5 100644
--- a/d2oracle/edit_test.go
+++ b/d2oracle/edit_test.go
@@ -1177,6 +1177,83 @@ b
   }
 }
 b: {style.fill: green}
+`,
+		},
+		{
+			name: "class-with-label",
+			text: `classes: {
+  user: {
+    label: ""
+  }
+}
+
+a.class: user
+`,
+			key:   `a.style.opacity`,
+			value: go2.Pointer(`0.5`),
+			exp: `classes: {
+  user: {
+    label: ""
+  }
+}
+
+a.class: user
+a.style.opacity: 0.5
+`,
+		},
+		{
+			name: "edge-class-with-label",
+			text: `classes: {
+  user: {
+    label: ""
+  }
+}
+
+a -> b: {
+  class: user
+}
+`,
+			key:   `(a -> b)[0].style.opacity`,
+			value: go2.Pointer(`0.5`),
+			exp: `classes: {
+  user: {
+    label: ""
+  }
+}
+
+a -> b: {
+  class: user
+  style.opacity: 0.5
+}
+`,
+		},
+		{
+			name: "var-with-label",
+			text: `vars: {
+  user: ""
+}
+
+a: ${user}
+`,
+			key:   `a.style.opacity`,
+			value: go2.Pointer(`0.5`),
+			exp: `vars: {
+  user: ""
+}
+
+a: ${user} {style.opacity: 0.5}
+`,
+		},
+		{
+			name: "glob-with-label",
+			text: `*.label: ""
+a
+`,
+			key:   `a.style.opacity`,
+			value: go2.Pointer(`0.5`),
+			exp: `*.label: ""
+a
+a.style.opacity: 0.5
 `,
 		},
 		{
diff --git a/testdata/d2oracle/TestSet/class-with-label.exp.json b/testdata/d2oracle/TestSet/class-with-label.exp.json
new file mode 100644
index 0000000000..1cfcb550d5
--- /dev/null
+++ b/testdata/d2oracle/TestSet/class-with-label.exp.json
@@ -0,0 +1,324 @@
+{
+  "graph": {
+    "name": "",
+    "isFolderOnly": false,
+    "ast": {
+      "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,0:0:0-8:0:77",
+      "nodes": [
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,0:0:0-4:1:40",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,0:0:0-0:7:7",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,0:0:0-0:7:7",
+                    "value": [
+                      {
+                        "string": "classes",
+                        "raw_string": "classes"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "map": {
+                "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,0:9:9-4:1:40",
+                "nodes": [
+                  {
+                    "map_key": {
+                      "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,1:2:13-3:3:38",
+                      "key": {
+                        "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,1:2:13-1:6:17",
+                        "path": [
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,1:2:13-1:6:17",
+                              "value": [
+                                {
+                                  "string": "user",
+                                  "raw_string": "user"
+                                }
+                              ]
+                            }
+                          }
+                        ]
+                      },
+                      "primary": {},
+                      "value": {
+                        "map": {
+                          "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,1:8:19-3:3:38",
+                          "nodes": [
+                            {
+                              "map_key": {
+                                "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,2:4:25-2:13:34",
+                                "key": {
+                                  "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,2:4:25-2:9:30",
+                                  "path": [
+                                    {
+                                      "unquoted_string": {
+                                        "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,2:4:25-2:9:30",
+                                        "value": [
+                                          {
+                                            "string": "label",
+                                            "raw_string": "label"
+                                          }
+                                        ]
+                                      }
+                                    }
+                                  ]
+                                },
+                                "primary": {},
+                                "value": {
+                                  "double_quoted_string": {
+                                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,2:11:32-2:13:34",
+                                    "value": null
+                                  }
+                                }
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  }
+                ]
+              }
+            }
+          }
+        },
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:0:42-6:13:55",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:0:42-6:7:49",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:0:42-6:1:43",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:2:44-6:7:49",
+                    "value": [
+                      {
+                        "string": "class",
+                        "raw_string": "class"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "unquoted_string": {
+                "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:9:51-6:13:55",
+                "value": [
+                  {
+                    "string": "user",
+                    "raw_string": "user"
+                  }
+                ]
+              }
+            }
+          }
+        },
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:0:56-7:20:76",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:0:56-7:15:71",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:0:56-7:1:57",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:2:58-7:7:63",
+                    "value": [
+                      {
+                        "string": "style",
+                        "raw_string": "style"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:8:64-7:15:71",
+                    "value": [
+                      {
+                        "string": "opacity",
+                        "raw_string": "opacity"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "number": {
+                "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:17:73-7:20:76",
+                "raw": "0.5",
+                "value": "1/2"
+              }
+            }
+          }
+        }
+      ]
+    },
+    "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": "a",
+        "id_val": "a",
+        "references": [
+          {
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:0:42-6:7:49",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:0:42-6:1:43",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,6:2:44-6:7:49",
+                    "value": [
+                      {
+                        "string": "class",
+                        "raw_string": "class"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "key_path_index": 0,
+            "map_key_edge_index": -1
+          },
+          {
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:0:56-7:15:71",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:0:56-7:1:57",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:2:58-7:7:63",
+                    "value": [
+                      {
+                        "string": "style",
+                        "raw_string": "style"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/class-with-label.d2,7:8:64-7:15:71",
+                    "value": [
+                      {
+                        "string": "opacity",
+                        "raw_string": "opacity"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "key_path_index": 0,
+            "map_key_edge_index": -1
+          }
+        ],
+        "attributes": {
+          "label": {
+            "value": ""
+          },
+          "labelDimensions": {
+            "width": 0,
+            "height": 0
+          },
+          "style": {
+            "opacity": {
+              "value": "0.5"
+            }
+          },
+          "near_key": null,
+          "shape": {
+            "value": "rectangle"
+          },
+          "direction": {
+            "value": ""
+          },
+          "constraint": null,
+          "classes": [
+            "user"
+          ]
+        },
+        "zIndex": 0
+      }
+    ]
+  },
+  "err": "<nil>"
+}
diff --git a/testdata/d2oracle/TestSet/edge-class-with-label.exp.json b/testdata/d2oracle/TestSet/edge-class-with-label.exp.json
new file mode 100644
index 0000000000..fde7a3b65f
--- /dev/null
+++ b/testdata/d2oracle/TestSet/edge-class-with-label.exp.json
@@ -0,0 +1,377 @@
+{
+  "graph": {
+    "name": "",
+    "isFolderOnly": false,
+    "ast": {
+      "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,0:0:0-10:0:89",
+      "nodes": [
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,0:0:0-4:1:40",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,0:0:0-0:7:7",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,0:0:0-0:7:7",
+                    "value": [
+                      {
+                        "string": "classes",
+                        "raw_string": "classes"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "map": {
+                "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,0:9:9-4:1:40",
+                "nodes": [
+                  {
+                    "map_key": {
+                      "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,1:2:13-3:3:38",
+                      "key": {
+                        "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,1:2:13-1:6:17",
+                        "path": [
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,1:2:13-1:6:17",
+                              "value": [
+                                {
+                                  "string": "user",
+                                  "raw_string": "user"
+                                }
+                              ]
+                            }
+                          }
+                        ]
+                      },
+                      "primary": {},
+                      "value": {
+                        "map": {
+                          "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,1:8:19-3:3:38",
+                          "nodes": [
+                            {
+                              "map_key": {
+                                "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,2:4:25-2:13:34",
+                                "key": {
+                                  "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,2:4:25-2:9:30",
+                                  "path": [
+                                    {
+                                      "unquoted_string": {
+                                        "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,2:4:25-2:9:30",
+                                        "value": [
+                                          {
+                                            "string": "label",
+                                            "raw_string": "label"
+                                          }
+                                        ]
+                                      }
+                                    }
+                                  ]
+                                },
+                                "primary": {},
+                                "value": {
+                                  "double_quoted_string": {
+                                    "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,2:11:32-2:13:34",
+                                    "value": null
+                                  }
+                                }
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  }
+                ]
+              }
+            }
+          }
+        },
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:0:42-9:1:88",
+            "edges": [
+              {
+                "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:0:42-6:6:48",
+                "src": {
+                  "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:0:42-6:1:43",
+                  "path": [
+                    {
+                      "unquoted_string": {
+                        "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:0:42-6:1:43",
+                        "value": [
+                          {
+                            "string": "a",
+                            "raw_string": "a"
+                          }
+                        ]
+                      }
+                    }
+                  ]
+                },
+                "src_arrow": "",
+                "dst": {
+                  "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:5:47-6:6:48",
+                  "path": [
+                    {
+                      "unquoted_string": {
+                        "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:5:47-6:6:48",
+                        "value": [
+                          {
+                            "string": "b",
+                            "raw_string": "b"
+                          }
+                        ]
+                      }
+                    }
+                  ]
+                },
+                "dst_arrow": ">"
+              }
+            ],
+            "primary": {},
+            "value": {
+              "map": {
+                "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:8:50-9:1:88",
+                "nodes": [
+                  {
+                    "map_key": {
+                      "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,7:2:54-7:13:65",
+                      "key": {
+                        "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,7:2:54-7:7:59",
+                        "path": [
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,7:2:54-7:7:59",
+                              "value": [
+                                {
+                                  "string": "class",
+                                  "raw_string": "class"
+                                }
+                              ]
+                            }
+                          }
+                        ]
+                      },
+                      "primary": {},
+                      "value": {
+                        "unquoted_string": {
+                          "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,7:9:61-7:13:65",
+                          "value": [
+                            {
+                              "string": "user",
+                              "raw_string": "user"
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "map_key": {
+                      "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,8:2:68-8:20:86",
+                      "key": {
+                        "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,8:2:68-8:15:81",
+                        "path": [
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,8:2:68-8:7:73",
+                              "value": [
+                                {
+                                  "string": "style",
+                                  "raw_string": "style"
+                                }
+                              ]
+                            }
+                          },
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,8:8:74-8:15:81",
+                              "value": [
+                                {
+                                  "string": "opacity",
+                                  "raw_string": "opacity"
+                                }
+                              ]
+                            }
+                          }
+                        ]
+                      },
+                      "primary": {},
+                      "value": {
+                        "number": {
+                          "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,8:17:83-8:20:86",
+                          "raw": "0.5",
+                          "value": "1/2"
+                        }
+                      }
+                    }
+                  }
+                ]
+              }
+            }
+          }
+        }
+      ]
+    },
+    "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": [
+      {
+        "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": {
+            "opacity": {
+              "value": "0.5"
+            }
+          },
+          "near_key": null,
+          "shape": {
+            "value": ""
+          },
+          "direction": {
+            "value": ""
+          },
+          "constraint": null,
+          "classes": [
+            "user"
+          ]
+        },
+        "zIndex": 0
+      }
+    ],
+    "objects": [
+      {
+        "id": "a",
+        "id_val": "a",
+        "references": [
+          {
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:0:42-6:1:43",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:0:42-6:1:43",
+                    "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/d2oracle/TestSet/edge-class-with-label.d2,6:5:47-6:6:48",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/edge-class-with-label.d2,6:5:47-6:6:48",
+                    "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
+      }
+    ]
+  },
+  "err": "<nil>"
+}
diff --git a/testdata/d2oracle/TestSet/glob-with-label.exp.json b/testdata/d2oracle/TestSet/glob-with-label.exp.json
new file mode 100644
index 0000000000..f41339c5c5
--- /dev/null
+++ b/testdata/d2oracle/TestSet/glob-with-label.exp.json
@@ -0,0 +1,245 @@
+{
+  "graph": {
+    "name": "",
+    "isFolderOnly": false,
+    "ast": {
+      "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,0:0:0-3:0:35",
+      "nodes": [
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,0:0:0-0:11:11",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,0:0:0-0:7:7",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,0:0:0-0:1:1",
+                    "value": [
+                      {
+                        "string": "*",
+                        "raw_string": "*"
+                      }
+                    ],
+                    "pattern": [
+                      "*"
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,0:2:2-0:7:7",
+                    "value": [
+                      {
+                        "string": "label",
+                        "raw_string": "label"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "double_quoted_string": {
+                "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,0:9:9-0:11:11",
+                "value": null
+              }
+            }
+          }
+        },
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,1:0:12-1:1:13",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,1:0:12-1:1:13",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,1:0:12-1:1:13",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {}
+          }
+        },
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:0:14-2:20:34",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:0:14-2:15:29",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:0:14-2:1:15",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:2:16-2:7:21",
+                    "value": [
+                      {
+                        "string": "style",
+                        "raw_string": "style"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:8:22-2:15:29",
+                    "value": [
+                      {
+                        "string": "opacity",
+                        "raw_string": "opacity"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "number": {
+                "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:17:31-2:20:34",
+                "raw": "0.5",
+                "value": "1/2"
+              }
+            }
+          }
+        }
+      ]
+    },
+    "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": "a",
+        "id_val": "a",
+        "references": [
+          {
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,1:0:12-1:1:13",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,1:0:12-1:1:13",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "key_path_index": 0,
+            "map_key_edge_index": -1
+          },
+          {
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:0:14-2:15:29",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:0:14-2:1:15",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:2:16-2:7:21",
+                    "value": [
+                      {
+                        "string": "style",
+                        "raw_string": "style"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/glob-with-label.d2,2:8:22-2:15:29",
+                    "value": [
+                      {
+                        "string": "opacity",
+                        "raw_string": "opacity"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "key_path_index": 0,
+            "map_key_edge_index": -1
+          }
+        ],
+        "attributes": {
+          "label": {
+            "value": ""
+          },
+          "labelDimensions": {
+            "width": 0,
+            "height": 0
+          },
+          "style": {
+            "opacity": {
+              "value": "0.5"
+            }
+          },
+          "near_key": null,
+          "shape": {
+            "value": "rectangle"
+          },
+          "direction": {
+            "value": ""
+          },
+          "constraint": null
+        },
+        "zIndex": 0
+      }
+    ]
+  },
+  "err": "<nil>"
+}
diff --git a/testdata/d2oracle/TestSet/var-with-label.exp.json b/testdata/d2oracle/TestSet/var-with-label.exp.json
new file mode 100644
index 0000000000..c31d315574
--- /dev/null
+++ b/testdata/d2oracle/TestSet/var-with-label.exp.json
@@ -0,0 +1,238 @@
+{
+  "graph": {
+    "name": "",
+    "isFolderOnly": false,
+    "ast": {
+      "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,0:0:0-5:0:54",
+      "nodes": [
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,0:0:0-2:1:20",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,0:0:0-0:4:4",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,0:0:0-0:4:4",
+                    "value": [
+                      {
+                        "string": "vars",
+                        "raw_string": "vars"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {},
+            "value": {
+              "map": {
+                "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,0:6:6-2:1:20",
+                "nodes": [
+                  {
+                    "map_key": {
+                      "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,1:2:10-1:10:18",
+                      "key": {
+                        "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,1:2:10-1:6:14",
+                        "path": [
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,1:2:10-1:6:14",
+                              "value": [
+                                {
+                                  "string": "user",
+                                  "raw_string": "user"
+                                }
+                              ]
+                            }
+                          }
+                        ]
+                      },
+                      "primary": {},
+                      "value": {
+                        "double_quoted_string": {
+                          "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,1:8:16-1:10:18",
+                          "value": null
+                        }
+                      }
+                    }
+                  }
+                ]
+              }
+            }
+          }
+        },
+        {
+          "map_key": {
+            "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:0:22-4:31:53",
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:0:22-4:1:23",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:0:22-4:1:23",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "primary": {
+              "unquoted_string": {
+                "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:3:25-4:4:26",
+                "value": [
+                  {
+                    "substitution": {
+                      "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:3:25-4:10:32",
+                      "spread": false,
+                      "path": [
+                        {
+                          "unquoted_string": {
+                            "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:5:27-4:9:31",
+                            "value": [
+                              {
+                                "string": "user",
+                                "raw_string": "user"
+                              }
+                            ]
+                          }
+                        }
+                      ]
+                    }
+                  }
+                ]
+              }
+            },
+            "value": {
+              "map": {
+                "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:11:33-4:31:53",
+                "nodes": [
+                  {
+                    "map_key": {
+                      "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:12:34-4:30:52",
+                      "key": {
+                        "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:12:34-4:25:47",
+                        "path": [
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:12:34-4:17:39",
+                              "value": [
+                                {
+                                  "string": "style",
+                                  "raw_string": "style"
+                                }
+                              ]
+                            }
+                          },
+                          {
+                            "unquoted_string": {
+                              "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:18:40-4:25:47",
+                              "value": [
+                                {
+                                  "string": "opacity",
+                                  "raw_string": "opacity"
+                                }
+                              ]
+                            }
+                          }
+                        ]
+                      },
+                      "primary": {},
+                      "value": {
+                        "number": {
+                          "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:27:49-4:30:52",
+                          "raw": "0.5",
+                          "value": "1/2"
+                        }
+                      }
+                    }
+                  }
+                ]
+              }
+            }
+          }
+        }
+      ]
+    },
+    "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": "a",
+        "id_val": "a",
+        "references": [
+          {
+            "key": {
+              "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:0:22-4:1:23",
+              "path": [
+                {
+                  "unquoted_string": {
+                    "range": "d2/testdata/d2oracle/TestSet/var-with-label.d2,4:0:22-4:1:23",
+                    "value": [
+                      {
+                        "string": "a",
+                        "raw_string": "a"
+                      }
+                    ]
+                  }
+                }
+              ]
+            },
+            "key_path_index": 0,
+            "map_key_edge_index": -1
+          }
+        ],
+        "attributes": {
+          "label": {
+            "value": ""
+          },
+          "labelDimensions": {
+            "width": 0,
+            "height": 0
+          },
+          "style": {
+            "opacity": {
+              "value": "0.5"
+            }
+          },
+          "near_key": null,
+          "shape": {
+            "value": "rectangle"
+          },
+          "direction": {
+            "value": ""
+          },
+          "constraint": null
+        },
+        "zIndex": 0
+      }
+    ]
+  },
+  "err": "<nil>"
+}