3 files changed,
40 insertions(+),
30 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2025-11-27 14:55:49 +0200
Change ID:
wrrouvntmlqttnxlkxyymwryyxmqwywv
Parent:
917fe25
jump to
| M | json2go.go |
| M | json2go_internal_test.go |
| M | json2go_test.go |
M
json2go.go
@@ -16,7 +16,8 @@ ErrInvalidStructName = errors.New("invalid struct name")
) type Transformer struct { - structName string + structName string + currentIndent int } func NewTransformer() *Transformer {@@ -32,6 +33,7 @@ return "", ErrInvalidStructName
} t.structName = structName + t.currentIndent = 0 var input any if err := json.Unmarshal([]byte(jsonStr), &input); err != nil {@@ -82,21 +84,27 @@ fieldName = "NotNamedField"
f.field = "NotNamedField" } + // increase indentation in case of building new struct + t.currentIndent++ fieldType := t.getGoType(fieldName, f.type_) + t.currentIndent-- // todo: toggle json tags generation jsonTag := fmt.Sprintf("`json:\"%s\"`", f.field) - // todo: figure out the indentation, since it might have nested struct + indent := strings.Repeat("\t", t.currentIndent+1) fields.WriteString(fmt.Sprintf( - "%s %s %s\n", + "%s%s %s %s\n", + indent, fieldName, fieldType, jsonTag, )) } - return fmt.Sprintf("struct {\n%s}", fields.String()) + return fmt.Sprintf("struct {\n%s%s}", + fields.String(), + strings.Repeat("\t", t.currentIndent)) } func (t *Transformer) getGoType(fieldName string, value any) string {
M
json2go_internal_test.go
@@ -14,8 +14,9 @@ "username": "user-ovich",
"age": float64(20), }, output: "struct {" + - field("Age", "int") + - field("Username", "string") + "\n}", + field(1, "Age", "int") + + field(1, "Username", "string") + + "\n}", }, "empty slice": { value: make([]any, 0),@@ -82,13 +83,13 @@ // only one value, because of the inconsistent ordering of maps
"active": true, }, output: "struct {" + - field("Active", "bool", "active") + + field(1, "Active", "bool", "active") + "\n}", }, "with no named field": { input: map[string]any{"": "user"}, output: "struct {" + - field("NotNamedField", "string", "NotNamedField") + + field(1, "NotNamedField", "string", "NotNamedField") + "\n}", }, }@@ -113,7 +114,7 @@ }{
"struct": { input: map[string]any{"field": false}, output: c + "struct {" + - field("Field", "bool") + "\n}", + field(1, "Field", "bool") + "\n}", }, "slice": { input: []any{"asdf", "jkl;"},
M
json2go_test.go
@@ -8,16 +8,17 @@ "strings"
"testing" ) -func field(name, type_ string, json_ ...string) string { +func field(indentLvl int, name, type_ string, json_ ...string) string { + indent := strings.Repeat("\t", indentLvl) if strings.Contains(type_, "struct") { - return fmt.Sprintf("\n%s %s", name, type_) + return fmt.Sprintf("\n%s%s %s", indent, name, type_) } tag := strings.ToLower(name) if len(json_) == 1 { tag = json_[0] } - return fmt.Sprintf("\n%s %s `json:\"%s\"`", name, type_, tag) + return fmt.Sprintf("\n%s%s %s `json:\"%s\"`", indent, name, type_, tag) } func TestTransformer_Transform(t *testing.T) {@@ -30,9 +31,9 @@ }{
"simple object": { input: `{"name": "Olex", "active": true, "age": 420}`, output: "type Out struct {" + - field("Active", "bool") + - field("Age", "int") + - field("Name", "string") + + field(1, "Active", "bool") + + field(1, "Age", "int") + + field(1, "Name", "string") + "\n}", }, "invalid json": {@@ -54,51 +55,51 @@ },
"snake_case to CamelCase": { input: `{"first_name": "Bob", "last_name": "Bobberson"}`, output: "type Out struct {" + - field("FirstName", "string", "first_name") + - field("LastName", "string", "last_name") + + field(1, "FirstName", "string", "first_name") + + field(1, "LastName", "string", "last_name") + "\n}", }, "nested object and array": { input: `{"user": {"name": "Alice", "score": 95.5}, "tags": ["go", "json"]}`, output: "type Out struct {" + - field("Tags", "[]string") + - field("User", "struct {") + - field("Name", "string") + - field("Score", "float64") + - "\n} `json:\"user\"`" + + field(1, "Tags", "[]string") + + field(1, "User", "struct {") + + field(2, "Name", "string") + + field(2, "Score", "float64") + + "\n\t} `json:\"user\"`" + "\n}", }, "empty nested object": { input: `{"user": {}}`, output: "type Out struct {" + - field("User", "struct {") + - "\n} `json:\"user\"`" + + field(1, "User", "struct {") + + "\n\t} `json:\"user\"`" + "\n}", }, "array of object": { input: `[{"name": "John"}, {"name": "Jane"}]`, output: "type Out []struct {" + - field("Name", "string") + + field(1, "Name", "string") + "\n}", }, "empty array": { input: `{"items": []}`, output: "type Out struct {" + - field("Items", "[]any") + + field(1, "Items", "[]any") + "\n}", }, "null": { input: `{"item": null}`, output: `type Out struct {` + - field("Item", "any") + + field(1, "Item", "any") + "\n}", }, "numbers": { input: `{"pos": 123, "neg": -321, "float": 420.69}`, output: "type Out struct {" + - field("Float", "float64") + - field("Neg", "int") + - field("Pos", "int") + + field(1, "Float", "float64") + + field(1, "Neg", "int") + + field(1, "Pos", "int") + "\n}", }, }