From 9e73ae201cb11e0d52078580b0e4876120223fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Gu=C3=AD=C3=B1ez?= Date: Thu, 22 Oct 2026 23:06:23 -0300 Subject: [PATCH 1/5] compiler: keep sql_table column types that match the column name A column's label defaults to its name, so compileSQLTable blanked the type whenever the two matched, including when the label was set explicitly (date: date). Record explicit labels and only blank the type when there is none. Fixes #1960 --- ci/release/changelogs/next.md | 2 + d2compiler/compile.go | 10 +- d2compiler/compile_test.go | 20 + .../sql_column_type_matches_name.exp.json | 480 ++++++++++++++++++ 4 files changed, 509 insertions(+), 3 deletions(-) create mode 100644 testdata/d2compiler/TestCompile/sql_column_type_matches_name.exp.json diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index d291ced933..c88500cda0 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -51,6 +51,8 @@ - Limit wildcard edge connections and selectors to bounded expansion work, returning a clear error before excessive fanout consumes resources. [#2926](https://github.com/d2lang/d2/pull/2926) + - Keep `sql_table` column types that match the column name, such as + `date: date`, instead of rendering an empty type. - decoding and assets: - Cap decompressed URL-encoded D2 input at 16 MiB. [#2902](https://github.com/d2lang/d2/pull/2902) - Bound image references, locators, fetched and decoded bytes, cached data, and diff --git a/d2compiler/compile.go b/d2compiler/compile.go index a871692b87..993193abf8 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -421,6 +421,7 @@ type compiler struct { err *d2parser.ParseError activeClassMaps map[*d2ir.Map]struct{} classMapsByRoot map[*d2ir.Map]map[string]*d2ir.Map + explicitLabels map[*d2graph.Attributes]struct{} ctx context.Context fatalErr error } @@ -793,6 +794,10 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) { attrs.Label.Value = scalar.ScalarString() } attrs.Label.MapKey = f.LastPrimaryKey() + if c.explicitLabels == nil { + c.explicitLabels = make(map[*d2graph.Attributes]struct{}) + } + c.explicitLabels[attrs] = struct{}{} } func (c *compiler) compilePosition(attrs *d2graph.Attributes, f *d2ir.Field) { @@ -1464,9 +1469,8 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) { return } typ := col.Label.Value - if typ == col.IDVal { - // Not great, AST should easily allow specifying alternate primary field - // as an explicit label should change the name. + // A column without an explicit label defaults it to its ID, which is not a type. + if _, ok := c.explicitLabels[&col.Attributes]; !ok && typ == col.IDVal { typ = "" } d2Col := d2target.SQLColumn{ diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 0be7759ced..23bd1ca462 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -2857,6 +2857,26 @@ x.y -> a.b: { assert.String(t, `Is()`, g.Objects[0].SQLTable.Columns[1].Name.Label) }, }, + { + name: "sql_column_type_matches_name", + + text: `time: { + shape: sql_table + id + created {constraint: primary_key} + date: date + key: key + key {constraint: unique} +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + cols := g.Objects[0].SQLTable.Columns + assert.String(t, ``, cols[0].Type.Label) + assert.String(t, ``, cols[1].Type.Label) + assert.String(t, `date`, cols[2].Type.Label) + assert.String(t, `key`, cols[3].Type.Label) + }, + }, { name: "nested_sql", diff --git a/testdata/d2compiler/TestCompile/sql_column_type_matches_name.exp.json b/testdata/d2compiler/TestCompile/sql_column_type_matches_name.exp.json new file mode 100644 index 0000000000..68b59206c8 --- /dev/null +++ b/testdata/d2compiler/TestCompile/sql_column_type_matches_name.exp.json @@ -0,0 +1,480 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:0:0-8:0:121", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:0:0-7:1:120", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:0:0-0:4:4", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:0:0-0:4:4", + "value": [ + { + "string": "time", + "raw_string": "time" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:6:6-7:1:120", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,1:2:10-1:18:26", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,1:2:10-1:7:15", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,1:2:10-1:7:15", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,1:9:17-1:18:26", + "value": [ + { + "string": "sql_table", + "raw_string": "sql_table" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,2:2:29-2:4:31", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,2:2:29-2:4:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,2:2:29-2:4:31", + "value": [ + { + "string": "id", + "raw_string": "id" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:2:34-3:35:67", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:2:34-3:9:41", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:2:34-3:9:41", + "value": [ + { + "string": "created", + "raw_string": "created" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:10:42-3:35:67", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:11:43-3:34:66", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:11:43-3:21:53", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:11:43-3:21:53", + "value": [ + { + "string": "constraint", + "raw_string": "constraint" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,3:23:55-3:34:66", + "value": [ + { + "string": "primary_key", + "raw_string": "primary_key" + } + ] + } + } + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,4:2:70-4:12:80", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,4:2:70-4:6:74", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,4:2:70-4:6:74", + "value": [ + { + "string": "date", + "raw_string": "date" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,4:8:76-4:12:80", + "value": [ + { + "string": "date", + "raw_string": "date" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,5:2:83-5:10:91", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,5:2:83-5:5:86", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,5:2:83-5:5:86", + "value": [ + { + "string": "key", + "raw_string": "key" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,5:7:88-5:10:91", + "value": [ + { + "string": "key", + "raw_string": "key" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:2:94-6:26:118", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:2:94-6:5:97", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:2:94-6:5:97", + "value": [ + { + "string": "key", + "raw_string": "key" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:6:98-6:26:118", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:7:99-6:25:117", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:7:99-6:17:109", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:7:99-6:17:109", + "value": [ + { + "string": "constraint", + "raw_string": "constraint" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,6:19:111-6:25:117", + "value": [ + { + "string": "unique", + "raw_string": "unique" + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "time", + "id_val": "time", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:0:0-0:4:4", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/sql_column_type_matches_name.d2,0:0:0-0:4:4", + "value": [ + { + "string": "time", + "raw_string": "time" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "sql_table": { + "columns": [ + { + "name": { + "label": "id", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "created", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": [ + "primary_key" + ], + "reference": "" + }, + { + "name": { + "label": "date", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "date", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "key", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "key", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": [ + "unique" + ], + "reference": "" + } + ] + }, + "attributes": { + "label": { + "value": "time" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "sql_table" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": null +} From e961cd93a5a36262b3a5aca2a1e0d40a8758c686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Gu=C3=AD=C3=B1ez?= Date: Thu, 22 Oct 2026 23:06:45 -0300 Subject: [PATCH 2/5] changelog: link #2950 --- ci/release/changelogs/next.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index c88500cda0..550f125cd6 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -52,7 +52,7 @@ returning a clear error before excessive fanout consumes resources. [#2926](https://github.com/d2lang/d2/pull/2926) - Keep `sql_table` column types that match the column name, such as - `date: date`, instead of rendering an empty type. + `date: date`, instead of rendering an empty type. [#2950](https://github.com/d2lang/d2/pull/2950) - decoding and assets: - Cap decompressed URL-encoded D2 input at 16 MiB. [#2902](https://github.com/d2lang/d2/pull/2902) - Bound image references, locators, fetched and decoded bytes, cached data, and From c62733a2845b27f7e077bb5b9214837650c379f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Gu=C3=AD=C3=B1ez?= Date: Fri, 23 Oct 2026 00:26:26 -0300 Subject: [PATCH 3/5] compiler: add hasExplicitLabel helper --- d2compiler/compile.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 993193abf8..e2cc25c3cd 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -800,6 +800,11 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) { c.explicitLabels[attrs] = struct{}{} } +func (c *compiler) hasExplicitLabel(attrs *d2graph.Attributes) bool { + _, ok := c.explicitLabels[attrs] + return ok +} + func (c *compiler) compilePosition(attrs *d2graph.Attributes, f *d2ir.Field) { if c.stopped() { return @@ -1470,7 +1475,7 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) { } typ := col.Label.Value // A column without an explicit label defaults it to its ID, which is not a type. - if _, ok := c.explicitLabels[&col.Attributes]; !ok && typ == col.IDVal { + if !c.hasExplicitLabel(&col.Attributes) && typ == col.IDVal { typ = "" } d2Col := d2target.SQLColumn{ From 9a9992812580c2386126a1a87297fc115afee53c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Gu=C3=AD=C3=B1ez?= Date: Fri, 23 Oct 2026 00:28:54 -0300 Subject: [PATCH 4/5] compiler: keep class field and method types that match the name A class field or method label defaults to its name, so compileClass dropped the field type, or replaced the return type with void, whenever the two matched, including when the label was set explicitly (date: date). Only fall back when there is no explicit label. Fixes #2951 --- ci/release/changelogs/next.md | 2 + d2compiler/compile.go | 7 +- d2compiler/compile_test.go | 21 ++ .../class_field_type_matches_name.exp.json | 328 ++++++++++++++++++ 4 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 testdata/d2compiler/TestCompile/class_field_type_matches_name.exp.json diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 550f125cd6..3f4e5254bf 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -53,6 +53,8 @@ [#2926](https://github.com/d2lang/d2/pull/2926) - Keep `sql_table` column types that match the column name, such as `date: date`, instead of rendering an empty type. [#2950](https://github.com/d2lang/d2/pull/2950) + - Keep `class` field types and method return types that match the name, such + as `date: date`, instead of dropping them. - decoding and assets: - Cap decompressed URL-encoded D2 input at 16 MiB. [#2902](https://github.com/d2lang/d2/pull/2902) - Bound image references, locators, fetched and decoded bytes, cached data, and diff --git a/d2compiler/compile.go b/d2compiler/compile.go index e2cc25c3cd..56050ee478 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -1417,9 +1417,10 @@ func (c *compiler) compileClass(obj *d2graph.Object) { } } + // A field or method without an explicit label defaults it to its ID, which is not a type. if !strings.Contains(f.IDVal, "(") { typ := f.Label.Value - if typ == f.IDVal { + if !c.hasExplicitLabel(&f.Attributes) && typ == f.IDVal { typ = "" } underline := f.Attributes.Style.Underline != nil && f.Attributes.Style.Underline.Value == "true" @@ -1430,10 +1431,8 @@ func (c *compiler) compileClass(obj *d2graph.Object) { Underline: underline, }) } else { - // TODO: Not great, AST should easily allow specifying alternate primary field - // as an explicit label should change the name. returnType := f.Label.Value - if returnType == f.IDVal { + if !c.hasExplicitLabel(&f.Attributes) && returnType == f.IDVal { returnType = "void" } underline := f.Attributes.Style.Underline != nil && f.Attributes.Style.Underline.Value == "true" diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 23bd1ca462..03ce69af99 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -2877,6 +2877,27 @@ x.y -> a.b: { assert.String(t, `key`, cols[3].Type.Label) }, }, + { + name: "class_field_type_matches_name", + + text: `Event: { + shape: class + id + date: date + +status: status + save() + now(): now() +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + class := g.Objects[0].Class + assert.String(t, ``, class.Fields[0].Type) + assert.String(t, `date`, class.Fields[1].Type) + assert.String(t, `status`, class.Fields[2].Type) + assert.String(t, `void`, class.Methods[0].Return) + assert.String(t, `now()`, class.Methods[1].Return) + }, + }, { name: "nested_sql", diff --git a/testdata/d2compiler/TestCompile/class_field_type_matches_name.exp.json b/testdata/d2compiler/TestCompile/class_field_type_matches_name.exp.json new file mode 100644 index 0000000000..cefa08378d --- /dev/null +++ b/testdata/d2compiler/TestCompile/class_field_type_matches_name.exp.json @@ -0,0 +1,328 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:0:0-8:0:86", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:0:0-7:1:85", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:0:0-0:5:5", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:0:0-0:5:5", + "value": [ + { + "string": "Event", + "raw_string": "Event" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:7:7-7:1:85", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,1:2:11-1:14:23", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,1:2:11-1:7:16", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,1:2:11-1:7:16", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,1:9:18-1:14:23", + "value": [ + { + "string": "class", + "raw_string": "class" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,2:2:26-2:4:28", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,2:2:26-2:4:28", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,2:2:26-2:4:28", + "value": [ + { + "string": "id", + "raw_string": "id" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,3:2:31-3:12:41", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,3:2:31-3:6:35", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,3:2:31-3:6:35", + "value": [ + { + "string": "date", + "raw_string": "date" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,3:8:37-3:12:41", + "value": [ + { + "string": "date", + "raw_string": "date" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,4:2:44-4:17:59", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,4:2:44-4:9:51", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,4:2:44-4:9:51", + "value": [ + { + "string": "+status", + "raw_string": "+status" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,4:11:53-4:17:59", + "value": [ + { + "string": "status", + "raw_string": "status" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,5:2:62-5:8:68", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,5:2:62-5:8:68", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,5:2:62-5:8:68", + "value": [ + { + "string": "save()", + "raw_string": "save()" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,6:2:71-6:14:83", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,6:2:71-6:7:76", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,6:2:71-6:7:76", + "value": [ + { + "string": "now()", + "raw_string": "now()" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,6:9:78-6:14:83", + "value": [ + { + "string": "now()", + "raw_string": "now()" + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "Event", + "id_val": "Event", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:0:0-0:5:5", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/class_field_type_matches_name.d2,0:0:0-0:5:5", + "value": [ + { + "string": "Event", + "raw_string": "Event" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "class": { + "fields": [ + { + "name": "id", + "type": "", + "visibility": "public", + "underline": false + }, + { + "name": "date", + "type": "date", + "visibility": "public", + "underline": false + }, + { + "name": "status", + "type": "status", + "visibility": "public", + "underline": false + } + ], + "methods": [ + { + "name": "save()", + "return": "void", + "visibility": "public", + "underline": false + }, + { + "name": "now()", + "return": "now()", + "visibility": "public", + "underline": false + } + ] + }, + "attributes": { + "label": { + "value": "Event" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "class" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": null +} From f488a0119d6562b2cae923548c91c4734e6189f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Gu=C3=AD=C3=B1ez?= Date: Fri, 23 Oct 2026 00:33:37 -0300 Subject: [PATCH 5/5] changelog: link #2952 --- ci/release/changelogs/next.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 3f4e5254bf..a3caa6955f 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -54,7 +54,7 @@ - Keep `sql_table` column types that match the column name, such as `date: date`, instead of rendering an empty type. [#2950](https://github.com/d2lang/d2/pull/2950) - Keep `class` field types and method return types that match the name, such - as `date: date`, instead of dropping them. + as `date: date`, instead of dropping them. [#2952](https://github.com/d2lang/d2/pull/2952) - decoding and assets: - Cap decompressed URL-encoded D2 input at 16 MiB. [#2902](https://github.com/d2lang/d2/pull/2902) - Bound image references, locators, fetched and decoded bytes, cached data, and