Merge pull request #2494 from alixander/fix-slkjdf

d2ir: fix imported glob leaf filter
This commit is contained in:
Alexander Wang 2025-04-16 07:52:00 -07:00 committed by GitHub
commit 0b584b2122
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 400 additions and 4 deletions

View file

@ -38,6 +38,7 @@
- fixes panic when classes were mixed with layers incorrectly [#2448](https://github.com/terrastruct/d2/pull/2448)
- fixes panic when gradient colors are used in sketch mode [#2481](https://github.com/terrastruct/d2/pull/2487)
- fixes panic using glob ampersand filters with composite values [#2489](https://github.com/terrastruct/d2/pull/2489)
- fixes leaf ampersand filter when used with imports [#2494](https://github.com/terrastruct/d2/pull/2494)
- Formatter:
- fixes substitutions in quotes surrounded by text [#2462](https://github.com/terrastruct/d2/pull/2462)
- CLI: fetch and render remote images of mimetype octet-stream correctly [#2370](https://github.com/terrastruct/d2/pull/2370)

View file

@ -1726,6 +1726,33 @@ k
expErr: `d2/testdata/d2compiler/TestCompile/composite-glob-filter.d2:3:3: glob filters cannot be composites
d2/testdata/d2compiler/TestCompile/composite-glob-filter.d2:3:3: glob filters cannot be composites`,
},
{
name: "imported-glob-leaf-filter",
text: `
***: {
&leaf: true
style: {
font-size: 30
}
}
a: {
...@x
}
`,
files: map[string]string{
"x.d2": `
b
`,
},
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.Equal(t, 2, len(g.Objects))
assert.Equal(t, "b", g.Objects[0].Label.Value)
assert.Equal(t, "a", g.Objects[1].Label.Value)
assert.Equal(t, "30", g.Objects[0].Style.FontSize.Value)
assert.Equal(t, (*d2graph.Scalar)(nil), g.Objects[1].Style.FontSize)
},
},
{
name: "import-nested-var",

View file

@ -981,7 +981,7 @@ func (c *compiler) _ampersandPropertyFilter(propName string, value string, node
c.errorf(key, `&leaf must be "true" or "false", got %q`, value)
return false
}
isLeaf := node.Map() == nil || !node.Map().IsContainer()
isLeaf := node.Map() == nil || !c.IsContainer(node.Map())
return isLeaf == boolVal
case "connected":
boolVal, err := strconv.ParseBool(value)

View file

@ -705,7 +705,7 @@ func (m *Map) FieldCountRecursive() int {
return acc
}
func (m *Map) IsContainer() bool {
func (c *compiler) IsContainer(m *Map) bool {
if m == nil {
return false
}
@ -714,6 +714,20 @@ func (m *Map) IsContainer() bool {
for _, ref := range f.References {
if ref.Primary() && ref.Context_.Key != nil && ref.Context_.Key.Value.Map != nil {
for _, n := range ref.Context_.Key.Value.Map.Nodes {
if n.MapKey == nil {
if n.Import != nil {
impn, ok := c.peekImport(n.Import)
if ok {
for _, f := range impn.Fields {
_, isReserved := d2ast.ReservedKeywords[f.Name.ScalarString()]
if !(isReserved && f.Name.IsUnquoted()) {
return true
}
}
}
}
continue
}
if len(n.MapKey.Edges) > 0 {
return true
}
@ -1333,7 +1347,7 @@ func (m *Map) createEdge(eid *EdgeID, refctx *RefContext, gctx *globContext, c *
if refctx.Edge.Src.HasMultiGlob() {
// If src has a double glob we only select leafs, those without children.
if src.Map().IsContainer() {
if c.IsContainer(src.Map()) {
continue
}
if NodeBoardKind(src) != "" || ParentBoard(src) != ParentBoard(dst) {
@ -1342,7 +1356,7 @@ func (m *Map) createEdge(eid *EdgeID, refctx *RefContext, gctx *globContext, c *
}
if refctx.Edge.Dst.HasMultiGlob() {
// If dst has a double glob we only select leafs, those without children.
if dst.Map().IsContainer() {
if c.IsContainer(dst.Map()) {
continue
}
if NodeBoardKind(dst) != "" || ParentBoard(src) != ParentBoard(dst) {

View file

@ -124,6 +124,53 @@ func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) {
return ir, true
}
func (c *compiler) peekImport(imp *d2ast.Import) (*Map, bool) {
impPath := imp.PathWithPre()
if impPath == "" && imp.Range != (d2ast.Range{}) {
return nil, false
}
if len(c.importStack) > 0 {
if path.Ext(impPath) != ".d2" {
impPath += ".d2"
}
if !filepath.IsAbs(impPath) {
impPath = path.Join(path.Dir(c.importStack[len(c.importStack)-1]), impPath)
}
}
var f fs.File
var err error
if c.fs == nil {
f, err = os.Open(impPath)
} else {
f, err = c.fs.Open(impPath)
}
if err != nil {
return nil, false
}
defer f.Close()
// Use a separate parse error to avoid polluting the main one
localErr := &d2parser.ParseError{}
ast, err := d2parser.Parse(impPath, f, &d2parser.ParseOptions{
UTF16Pos: c.utf16Pos,
ParseError: localErr,
})
if err != nil {
return nil, false
}
ir := &Map{}
ir.initRoot()
ir.parent.(*Field).References[0].Context_.Scope = ast
c.compileMap(ir, ast, ast)
return ir, true
}
func nilScopeMap(n Node) {
switch n := n.(type) {
case *Map:

View file

@ -0,0 +1,307 @@
{
"graph": {
"name": "",
"isFolderOnly": false,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,0:0:0-10:0:71",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,1:0:1-6:1:56",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,1:0:1-1:3:4",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,1:0:1-1:3:4",
"value": [
{
"string": "***",
"raw_string": "***"
}
],
"pattern": [
"*",
"",
"*",
"",
"*"
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,1:5:6-6:1:56",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,2:2:10-2:13:21",
"ampersand": true,
"key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,2:3:11-2:7:15",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,2:3:11-2:7:15",
"value": [
{
"string": "leaf",
"raw_string": "leaf"
}
]
}
}
]
},
"primary": {},
"value": {
"boolean": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,2:9:17-2:13:21",
"value": true
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,3:2:24-5:3:54",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,3:2:24-3:7:29",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,3:2:24-3:7:29",
"value": [
{
"string": "style",
"raw_string": "style"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,3:9:31-5:3:54",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,4:4:37-4:17:50",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,4:4:37-4:13:46",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,4:4:37-4:13:46",
"value": [
{
"string": "font-size",
"raw_string": "font-size"
}
]
}
}
]
},
"primary": {},
"value": {
"number": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,4:15:48-4:17:50",
"raw": "30",
"value": "30"
}
}
}
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,7:0:57-9:1:70",
"key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,7:0:57-7:1:58",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,7:0:57-7:1:58",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,7:3:60-9:1:70",
"nodes": [
{
"import": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,8:1:63-8:6:68",
"spread": true,
"pre": "",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,8:5:67-8:6:68",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
}
}
]
}
}
}
}
]
},
"root": {
"id": "",
"id_val": "",
"attributes": {
"label": {
"value": ""
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"iconStyle": {},
"near_key": null,
"shape": {
"value": ""
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
"edges": null,
"objects": [
{
"id": "b",
"id_val": "b",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile/x.d2,1:0:1-1:1:2",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/x.d2,1:0:1-1:1:2",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "b"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {
"fontSize": {
"value": "30"
}
},
"iconStyle": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "a",
"id_val": "a",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,7:0:57-7:1:58",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile/imported-glob-leaf-filter.d2,7:0:57-7:1:58",
"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": {},
"iconStyle": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
},
"err": null
}