all repos

json2go @ e64121e986feae9f6224469c4d0ae8993ed7f22b

convert json to go type annotations
3 files changed, 61 insertions(+), 81 deletions(-)
refactor!: inline all nested types
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-07-11 13:56:41 +0300
Authored at: 2026-07-11 13:56:30 +0300
Change ID: ktnmmslzwnlpwqlorwrnqxknyxwnmyky
Parent: c2472d6
M json2go_test.go
···
        81
        81
         				if !strings.Contains(result, "Tags []string") {

      
        82
        82
         					t.Errorf("missing Tags field")

      
        83
        83
         				}

      
        84
        
        -				if !strings.Contains(result, "User OutUser") {

      
        85
        
        -					t.Errorf("missing User field")

      
        
        84
        +				if !strings.Contains(result, "User struct {") {

      
        
        85
        +					t.Errorf("missing inline User struct")

      
        86
        86
         				}

      
        87
        
        -				if !strings.Contains(result, "type OutUser struct") {

      
        88
        
        -					t.Errorf("missing OutUser struct")

      
        
        87
        +				if !strings.Contains(result, "Name string `json:\"name\"`") {

      
        
        88
        +					t.Errorf("missing Name field in inline struct")

      
        89
        89
         				}

      
        90
        90
         			},

      
        91
        91
         		},

      ···
        95
        95
         				if !strings.Contains(result, "type Out struct") {

      
        96
        96
         					t.Errorf("missing Out struct")

      
        97
        97
         				}

      
        98
        
        -				if !strings.Contains(result, "type OutUser struct") {

      
        99
        
        -					t.Errorf("missing OutUser struct")

      
        
        98
        +				if !strings.Contains(result, "User struct {") {

      
        
        99
        +					t.Errorf("missing inline User struct")

      
        100
        100
         				}

      
        101
        101
         			},

      
        102
        102
         		},

      
        103
        103
         		"array of object": {

      
        104
        104
         			input: `[{"name": "John"}, {"name": "Jane"}]`,

      
        105
        105
         			check: func(t *testing.T, result string) {

      
        106
        
        -				if !strings.Contains(result, "type Out []OutItem") {

      
        107
        
        -					t.Errorf("missing Out array type")

      
        
        106
        +				if !strings.Contains(result, "type Out []struct {") {

      
        
        107
        +					t.Errorf("missing Out array type with inline struct, got: %s", result)

      
        108
        108
         				}

      
        109
        
        -				if !strings.Contains(result, "type OutItem struct") {

      
        110
        
        -					t.Errorf("missing OutItem struct")

      
        
        109
        +				if !strings.Contains(result, "Name string `json:\"name\"`") {

      
        
        110
        +					t.Errorf("missing Name field")

      
        111
        111
         				}

      
        112
        112
         			},

      
        113
        113
         		},

      
M transpiler.go
···
        11
        11
         func NewTranspiler() *Transpiler { return &Transpiler{} }

      
        12
        12
         

      
        13
        13
         // Transpile converts a [Value] AST to Go type definitions.

      
        14
        
        -// Nested types are emitted after the parent struct.

      
        15
        14
         func (t *Transpiler) Transpile(structName string, v Value, includeTags bool) (string, error) {

      
        16
        15
         	var buf strings.Builder

      
        17
        
        -	var nested strings.Builder

      
        
        16
        +	buf.WriteString("type ")

      
        
        17
        +	buf.WriteString(structName)

      
        18
        18
         

      
        19
        19
         	switch v.Kind {

      
        20
        20
         	case ArrayValue:

      
        
        21
        +		buf.WriteString(" [")

      
        21
        22
         		if len(v.Array) == 0 {

      
        22
        
        -			buf.WriteString("type ")

      
        23
        
        -			buf.WriteString(structName)

      
        24
        
        -			buf.WriteString(" []any")

      
        
        23
        +			buf.WriteString("]any")

      
        25
        24
         		} else {

      
        26
        
        -			itemType := t.writeWithNested(&buf, &nested, structName+"Item", v.Array[0], includeTags)

      
        27
        
        -			buf.WriteString("type ")

      
        28
        
        -			buf.WriteString(structName)

      
        29
        
        -			buf.WriteString(" []")

      
        30
        
        -			buf.WriteString(itemType)

      
        
        25
        +			buf.WriteByte(']')

      
        
        26
        +			t.writeInlineType(&buf, structName+"Item", v.Array[0], includeTags)

      
        31
        27
         		}

      
        32
        28
         

      
        33
        29
         	case ObjectValue:

      
        34
        
        -		t.writeStructDef(&buf, &nested, structName, v.Object, includeTags)

      
        
        30
        +		buf.WriteByte(' ')

      
        
        31
        +		t.writeInlineStruct(&buf, structName, v.Object, includeTags)

      
        35
        32
         

      
        36
        33
         	default:

      
        37
        
        -		scalarType := t.inferType(structName, v)

      
        38
        
        -		buf.WriteString("type ")

      
        39
        
        -		buf.WriteString(structName)

      
        40
        34
         		buf.WriteByte(' ')

      
        41
        
        -		buf.WriteString(scalarType)

      
        
        35
        +		t.writeScalarType(&buf, v)

      
        42
        36
         	}

      
        43
        37
         

      
        44
        
        -	if nested.Len() > 0 && buf.Len() > 0 {

      
        45
        
        -		buf.WriteString("\n\n")

      
        46
        
        -		buf.WriteString(nested.String())

      
        47
        
        -	}

      
        48
        38
         	return buf.String(), nil

      
        49
        39
         }

      
        50
        40
         

      
        51
        
        -func (t *Transpiler) writeWithNested(buf, nested *strings.Builder, name string, v Value, includeTags bool) string {

      
        
        41
        +func (t *Transpiler) writeInlineType(buf *strings.Builder, name string, v Value, includeTags bool) {

      
        52
        42
         	switch v.Kind {

      
        53
        43
         	case ObjectValue:

      
        54
        
        -		t.writeStructDef(nested, nested, name, v.Object, includeTags)

      
        55
        
        -		return name

      
        
        44
        +		t.writeInlineStruct(buf, name, v.Object, includeTags)

      
        56
        45
         

      
        57
        46
         	case ArrayValue:

      
        
        47
        +		buf.WriteByte('[')

      
        58
        48
         		if len(v.Array) == 0 {

      
        59
        
        -			return "[]any"

      
        
        49
        +			buf.WriteString("]any")

      
        
        50
        +		} else {

      
        
        51
        +			buf.WriteByte(']')

      
        
        52
        +			t.writeInlineType(buf, name+"Item", v.Array[0], includeTags)

      
        60
        53
         		}

      
        61
        
        -		itemType := t.writeWithNested(buf, nested, name+"Item", v.Array[0], includeTags)

      
        62
        
        -		return "[]" + itemType

      
        
        54
        +

      
        
        55
        +	default:

      
        
        56
        +		t.writeScalarType(buf, v)

      
        63
        57
         	}

      
        64
        
        -	return t.inferType(name, v)

      
        65
        58
         }

      
        66
        59
         

      
        67
        
        -func (t *Transpiler) writeStructDef(buf, nested *strings.Builder, name string, fields []Field, includeTags bool) {

      
        68
        
        -	if buf.Len() > 0 {

      
        69
        
        -		buf.WriteString("\n\n")

      
        70
        
        -	}

      
        71
        
        -

      
        72
        
        -	buf.WriteString("type ")

      
        73
        
        -	buf.WriteString(name)

      
        74
        
        -	buf.WriteString(" struct {\n")

      
        
        60
        +func (t *Transpiler) writeInlineStruct(buf *strings.Builder, name string, fields []Field, includeTags bool) {

      
        
        61
        +	buf.WriteString("struct {\n")

      
        75
        62
         	for _, f := range fields {

      
        76
        63
         		fieldName := t.sanitizeFieldName(f.K)

      
        77
        
        -		fieldType := t.writeWithNested(buf, nested, name+fieldName, f.V, includeTags)

      
        
        64
        +		buf.WriteByte('\t')

      
        
        65
        +		buf.WriteString(fieldName)

      
        
        66
        +		buf.WriteByte(' ')

      
        
        67
        +		t.writeInlineType(buf, name+fieldName, f.V, includeTags)

      
        78
        68
         		if includeTags {

      
        79
        
        -			buf.WriteByte('\t')

      
        80
        
        -			buf.WriteString(fieldName)

      
        81
        
        -			buf.WriteByte(' ')

      
        82
        
        -			buf.WriteString(fieldType)

      
        83
        69
         			buf.WriteString(" `json:\"")

      
        84
        70
         			buf.WriteString(f.K)

      
        85
        
        -			buf.WriteString("\"`\n")

      
        86
        
        -		} else {

      
        87
        
        -			buf.WriteByte('\t')

      
        88
        
        -			buf.WriteString(fieldName)

      
        89
        
        -			buf.WriteByte(' ')

      
        90
        
        -			buf.WriteString(fieldType)

      
        91
        
        -			buf.WriteByte('\n')

      
        
        71
        +			buf.WriteString("\"`")

      
        92
        72
         		}

      
        
        73
        +		buf.WriteByte('\n')

      
        93
        74
         	}

      
        94
        
        -	buf.WriteString("}")

      
        
        75
        +	buf.WriteByte('}')

      
        95
        76
         }

      
        96
        77
         

      
        97
        
        -func (t *Transpiler) inferType(name string, v Value) string {

      
        
        78
        +func (t *Transpiler) writeScalarType(buf *strings.Builder, v Value) {

      
        98
        79
         	switch v.Kind {

      
        99
        
        -	case ObjectValue:

      
        100
        
        -		return name

      
        101
        
        -	case ArrayValue:

      
        102
        
        -		if len(v.Array) == 0 {

      
        103
        
        -			return "[]any"

      
        104
        
        -		}

      
        105
        
        -		itemType := t.inferType(name+"Item", v.Array[0])

      
        106
        
        -		return "[]" + itemType

      
        107
        80
         	case StringValue:

      
        108
        
        -		return "string"

      
        
        81
        +		buf.WriteString("string")

      
        109
        82
         	case NumberValue:

      
        110
        
        -		return "int"

      
        
        83
        +		buf.WriteString("int")

      
        111
        84
         	case DecimalValue:

      
        112
        
        -		return "float64"

      
        
        85
        +		buf.WriteString("float64")

      
        113
        86
         	case BoolValue:

      
        114
        
        -		return "bool"

      
        115
        
        -	case NullValue:

      
        116
        
        -		return "any"

      
        
        87
        +		buf.WriteString("bool")

      
        117
        88
         	default:

      
        118
        
        -		return "any"

      
        
        89
        +		buf.WriteString("any")

      
        119
        90
         	}

      
        120
        91
         }

      
        121
        92
         

      
M transpiler_test.go
···
        51
        51
         				if !strings.Contains(result, "type Response struct") {

      
        52
        52
         					t.Errorf("missing Response struct")

      
        53
        53
         				}

      
        54
        
        -				if !strings.Contains(result, "type ResponseUser struct") {

      
        55
        
        -					t.Errorf("missing ResponseUser struct")

      
        
        54
        +				if !strings.Contains(result, "Name string `json:\"name\"`") {

      
        
        55
        +					t.Errorf("missing Name field")

      
        
        56
        +				}

      
        
        57
        +				if !strings.Contains(result, "Active bool `json:\"active\"`") {

      
        
        58
        +					t.Errorf("missing Active field")

      
        56
        59
         				}

      
        57
        
        -				if !strings.Contains(result, "User ResponseUser `json:\"user\"`") {

      
        58
        
        -					t.Errorf("missing User field")

      
        
        60
        +				if !strings.Contains(result, "User struct {") {

      
        
        61
        +					t.Errorf("missing inline User struct")

      
        59
        62
         				}

      
        60
        63
         			},

      
        61
        64
         		},

      ···
        84
        87
         				}},

      
        85
        88
         			},

      
        86
        89
         			check: func(t *testing.T, result string) {

      
        87
        
        -				if !strings.Contains(result, "type UsersItem struct") {

      
        88
        
        -					t.Errorf("missing UsersItem struct in: %s", result)

      
        
        90
        +				if !strings.Contains(result, "type Users []struct {") {

      
        
        91
        +					t.Errorf("missing Users array type with inline struct, got: %s", result)

      
        89
        92
         				}

      
        90
        93
         				if !strings.Contains(result, "Id int `json:\"id\"`") {

      
        91
        94
         					t.Errorf("missing Id field")

      ···
        171
        174
         				if !strings.Contains(result, "type Response struct") {

      
        172
        175
         					t.Errorf("missing Response struct")

      
        173
        176
         				}

      
        174
        
        -				if !strings.Contains(result, "type ResponseUser struct") {

      
        175
        
        -					t.Errorf("missing ResponseUser struct")

      
        
        177
        +				if !strings.Contains(result, "User struct {") {

      
        
        178
        +					t.Errorf("missing inline User struct")

      
        
        179
        +				}

      
        
        180
        +				if !strings.Contains(result, "Name string\n") {

      
        
        181
        +					t.Errorf("missing Name field")

      
        
        182
        +				}

      
        
        183
        +				if !strings.Contains(result, "Active bool\n") {

      
        
        184
        +					t.Errorf("missing Active field")

      
        176
        185
         				}

      
        177
        186
         				if strings.Contains(result, "`json:") {

      
        178
        187
         					t.Errorf("should not have json tags")