+12
-4
json2go.go
+12
-4
json2go.go
···
16
)
17
18
type Transformer struct {
19
-
structName string
20
}
21
22
func NewTransformer() *Transformer {
···
32
}
33
34
t.structName = structName
35
36
var input any
37
if err := json.Unmarshal([]byte(jsonStr), &input); err != nil {
···
82
f.field = "NotNamedField"
83
}
84
85
fieldType := t.getGoType(fieldName, f.type_)
86
87
// todo: toggle json tags generation
88
jsonTag := fmt.Sprintf("`json:\"%s\"`", f.field)
89
90
-
// todo: figure out the indentation, since it might have nested struct
91
fields.WriteString(fmt.Sprintf(
92
-
"%s %s %s\n",
93
fieldName,
94
fieldType,
95
jsonTag,
96
))
97
}
98
99
-
return fmt.Sprintf("struct {\n%s}", fields.String())
100
}
101
102
func (t *Transformer) getGoType(fieldName string, value any) string {
···
16
)
17
18
type Transformer struct {
19
+
structName string
20
+
currentIndent int
21
}
22
23
func NewTransformer() *Transformer {
···
33
}
34
35
t.structName = structName
36
+
t.currentIndent = 0
37
38
var input any
39
if err := json.Unmarshal([]byte(jsonStr), &input); err != nil {
···
84
f.field = "NotNamedField"
85
}
86
87
+
// increase indentation in case of building new struct
88
+
t.currentIndent++
89
fieldType := t.getGoType(fieldName, f.type_)
90
+
t.currentIndent--
91
92
// todo: toggle json tags generation
93
jsonTag := fmt.Sprintf("`json:\"%s\"`", f.field)
94
95
+
indent := strings.Repeat("\t", t.currentIndent+1)
96
fields.WriteString(fmt.Sprintf(
97
+
"%s%s %s %s\n",
98
+
indent,
99
fieldName,
100
fieldType,
101
jsonTag,
102
))
103
}
104
105
+
return fmt.Sprintf("struct {\n%s%s}",
106
+
fields.String(),
107
+
strings.Repeat("\t", t.currentIndent))
108
}
109
110
func (t *Transformer) getGoType(fieldName string, value any) string {
+6
-5
json2go_internal_test.go
+6
-5
json2go_internal_test.go
···
14
"age": float64(20),
15
},
16
output: "struct {" +
17
-
field("Age", "int") +
18
-
field("Username", "string") + "\n}",
19
},
20
"empty slice": {
21
value: make([]any, 0),
···
82
"active": true,
83
},
84
output: "struct {" +
85
-
field("Active", "bool", "active") +
86
"\n}",
87
},
88
"with no named field": {
89
input: map[string]any{"": "user"},
90
output: "struct {" +
91
-
field("NotNamedField", "string", "NotNamedField") +
92
"\n}",
93
},
94
}
···
113
"struct": {
114
input: map[string]any{"field": false},
115
output: c + "struct {" +
116
-
field("Field", "bool") + "\n}",
117
},
118
"slice": {
119
input: []any{"asdf", "jkl;"},
···
14
"age": float64(20),
15
},
16
output: "struct {" +
17
+
field(1, "Age", "int") +
18
+
field(1, "Username", "string") +
19
+
"\n}",
20
},
21
"empty slice": {
22
value: make([]any, 0),
···
83
"active": true,
84
},
85
output: "struct {" +
86
+
field(1, "Active", "bool", "active") +
87
"\n}",
88
},
89
"with no named field": {
90
input: map[string]any{"": "user"},
91
output: "struct {" +
92
+
field(1, "NotNamedField", "string", "NotNamedField") +
93
"\n}",
94
},
95
}
···
114
"struct": {
115
input: map[string]any{"field": false},
116
output: c + "struct {" +
117
+
field(1, "Field", "bool") + "\n}",
118
},
119
"slice": {
120
input: []any{"asdf", "jkl;"},
+22
-21
json2go_test.go
+22
-21
json2go_test.go
···
8
"testing"
9
)
10
11
-
func field(name, type_ string, json_ ...string) string {
12
if strings.Contains(type_, "struct") {
13
-
return fmt.Sprintf("\n%s %s", name, type_)
14
}
15
16
tag := strings.ToLower(name)
17
if len(json_) == 1 {
18
tag = json_[0]
19
}
20
-
return fmt.Sprintf("\n%s %s `json:\"%s\"`", name, type_, tag)
21
}
22
23
func TestTransformer_Transform(t *testing.T) {
···
30
"simple object": {
31
input: `{"name": "Olex", "active": true, "age": 420}`,
32
output: "type Out struct {" +
33
-
field("Active", "bool") +
34
-
field("Age", "int") +
35
-
field("Name", "string") +
36
"\n}",
37
},
38
"invalid json": {
···
54
"snake_case to CamelCase": {
55
input: `{"first_name": "Bob", "last_name": "Bobberson"}`,
56
output: "type Out struct {" +
57
-
field("FirstName", "string", "first_name") +
58
-
field("LastName", "string", "last_name") +
59
"\n}",
60
},
61
"nested object and array": {
62
input: `{"user": {"name": "Alice", "score": 95.5}, "tags": ["go", "json"]}`,
63
output: "type Out struct {" +
64
-
field("Tags", "[]string") +
65
-
field("User", "struct {") +
66
-
field("Name", "string") +
67
-
field("Score", "float64") +
68
-
"\n} `json:\"user\"`" +
69
"\n}",
70
},
71
"empty nested object": {
72
input: `{"user": {}}`,
73
output: "type Out struct {" +
74
-
field("User", "struct {") +
75
-
"\n} `json:\"user\"`" +
76
"\n}",
77
},
78
"array of object": {
79
input: `[{"name": "John"}, {"name": "Jane"}]`,
80
output: "type Out []struct {" +
81
-
field("Name", "string") +
82
"\n}",
83
},
84
"empty array": {
85
input: `{"items": []}`,
86
output: "type Out struct {" +
87
-
field("Items", "[]any") +
88
"\n}",
89
},
90
"null": {
91
input: `{"item": null}`,
92
output: `type Out struct {` +
93
-
field("Item", "any") +
94
"\n}",
95
},
96
"numbers": {
97
input: `{"pos": 123, "neg": -321, "float": 420.69}`,
98
output: "type Out struct {" +
99
-
field("Float", "float64") +
100
-
field("Neg", "int") +
101
-
field("Pos", "int") +
102
"\n}",
103
},
104
}
···
8
"testing"
9
)
10
11
+
func field(indentLvl int, name, type_ string, json_ ...string) string {
12
+
indent := strings.Repeat("\t", indentLvl)
13
if strings.Contains(type_, "struct") {
14
+
return fmt.Sprintf("\n%s%s %s", indent, name, type_)
15
}
16
17
tag := strings.ToLower(name)
18
if len(json_) == 1 {
19
tag = json_[0]
20
}
21
+
return fmt.Sprintf("\n%s%s %s `json:\"%s\"`", indent, name, type_, tag)
22
}
23
24
func TestTransformer_Transform(t *testing.T) {
···
31
"simple object": {
32
input: `{"name": "Olex", "active": true, "age": 420}`,
33
output: "type Out struct {" +
34
+
field(1, "Active", "bool") +
35
+
field(1, "Age", "int") +
36
+
field(1, "Name", "string") +
37
"\n}",
38
},
39
"invalid json": {
···
55
"snake_case to CamelCase": {
56
input: `{"first_name": "Bob", "last_name": "Bobberson"}`,
57
output: "type Out struct {" +
58
+
field(1, "FirstName", "string", "first_name") +
59
+
field(1, "LastName", "string", "last_name") +
60
"\n}",
61
},
62
"nested object and array": {
63
input: `{"user": {"name": "Alice", "score": 95.5}, "tags": ["go", "json"]}`,
64
output: "type Out struct {" +
65
+
field(1, "Tags", "[]string") +
66
+
field(1, "User", "struct {") +
67
+
field(2, "Name", "string") +
68
+
field(2, "Score", "float64") +
69
+
"\n\t} `json:\"user\"`" +
70
"\n}",
71
},
72
"empty nested object": {
73
input: `{"user": {}}`,
74
output: "type Out struct {" +
75
+
field(1, "User", "struct {") +
76
+
"\n\t} `json:\"user\"`" +
77
"\n}",
78
},
79
"array of object": {
80
input: `[{"name": "John"}, {"name": "Jane"}]`,
81
output: "type Out []struct {" +
82
+
field(1, "Name", "string") +
83
"\n}",
84
},
85
"empty array": {
86
input: `{"items": []}`,
87
output: "type Out struct {" +
88
+
field(1, "Items", "[]any") +
89
"\n}",
90
},
91
"null": {
92
input: `{"item": null}`,
93
output: `type Out struct {` +
94
+
field(1, "Item", "any") +
95
"\n}",
96
},
97
"numbers": {
98
input: `{"pos": 123, "neg": -321, "float": 420.69}`,
99
output: "type Out struct {" +
100
+
field(1, "Float", "float64") +
101
+
field(1, "Neg", "int") +
102
+
field(1, "Pos", "int") +
103
"\n}",
104
},
105
}