Skip to content

Commit

Permalink
Merge pull request #14 from alehechka/feature/alphabetical-order
Browse files Browse the repository at this point in the history
Alphabetical Key Sorting
  • Loading branch information
alehechka authored Jul 4, 2022
2 parents 678661f + a843fa5 commit c9145c7
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 36 deletions.
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ json2go generate --url="https://gorest.co.in/public/v2/users"

### CLI Arguments

| Argument | Example | Type | Purpose | Default |
| ---------------- | ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| File name | `--file=example.json` | `string` | Valid path to local file on disk |
| URL | `--url="https://example.com` | `string` | Valid URL that JSON can be fetched via GET request from. |
| Root Object Name | `--root=RootObject` | `string` | Name for top-level object in JSON payload | `Root` |
| Package Name | `--package=api` | `string` | Name of package to generate types into. A nested package path is valid | `main` |
| Output File Name | `--output` | `string` | The name of the file that is generated. If a file is provided as input, will use matching name unless explicitly provided. The ".go" extension is not required and will be automatically appended. | `types.go` |
| Time Format | `--time=2006-01-02` | `string` | Time format to use while parsing strings for potential time.Time variables. View time.Time constants for possible defaults: https://pkg.go.dev/time#pkg-constants | `RFC3339` |
| Omit Empty | `--omitempty` | `bool` | Appends the omitempty to all object variable tags. | `false` |
| Debug logging | `--debug` | `bool` | Will output debugging console logs. | `false` |
| Quiet | `--quiet` | `bool` | Will quiet fatal errors. | `false` |
| STDOUT | `--out` | `bool` | Instead of generating a Go file, will instead print the contents to STDOUT | `false` |
| Argument | Example | Type | Purpose | Default |
| ------------------ | ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| File name | `--file=example.json` | `string` | Valid path to local file on disk |
| URL | `--url="https://example.com` | `string` | Valid URL that JSON can be fetched via GET request from. |
| Root Object Name | `--root=RootObject` | `string` | Name for top-level object in JSON payload | `Root` |
| Package Name | `--package=api` | `string` | Name of package to generate types into. A nested package path is valid | `main` |
| Output File Name | `--output` | `string` | The name of the file that is generated. If a file is provided as input, will use matching name unless explicitly provided. The ".go" extension is not required and will be automatically appended. | `types.go` |
| Time Format | `--time=2006-01-02` | `string` | Time format to use while parsing strings for potential time.Time variables. View time.Time constants for possible defaults: https://pkg.go.dev/time#pkg-constants | `RFC3339` |
| Omit Empty | `--omitempty` | `bool` | Appends the omitempty to all object variable tags. | `false` |
| Alphabetical Order | `--alpha` | `bool` | Sorts all keys into alphabetical order before generation. | `false` |
| Debug logging | `--debug` | `bool` | Will output debugging console logs. | `false` |
| Quiet | `--quiet` | `bool` | Will quiet fatal errors. | `false` |
| STDOUT | `--out` | `bool` | Instead of generating a Go file, will instead print the contents to STDOUT | `false` |

### Local Development

Expand Down
27 changes: 17 additions & 10 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ import (
)

const (
urlFlag = "url"
fileFlag = "file"
rootFlag = "root"
packageFlag = "package"
outputFileFlag = "output"
debugFlag = "debug"
quietFlag = "quiet"
stdoutFlag = "out"
timeFormatFlag = "time"
omitEmptyFlag = "omitempty"
urlFlag = "url"
fileFlag = "file"
rootFlag = "root"
packageFlag = "package"
outputFileFlag = "output"
debugFlag = "debug"
quietFlag = "quiet"
stdoutFlag = "out"
timeFormatFlag = "time"
omitEmptyFlag = "omitempty"
alphabeticalFlag = "alphabetical"
)

var generateFlags = []cli.Flag{
Expand Down Expand Up @@ -62,6 +63,11 @@ var generateFlags = []cli.Flag{
Name: omitEmptyFlag,
Usage: "Appends the omitempty to all object variable tags.",
},
&cli.BoolFlag{
Name: alphabeticalFlag,
Aliases: []string{"a", "alpha"},
Usage: "Sorts all keys into alphabetical order before generation.",
},
&cli.BoolFlag{
Name: debugFlag,
Usage: "Log debug messages.",
Expand Down Expand Up @@ -93,6 +99,7 @@ func generateTypes(ctx *cli.Context) (err error) {
OutputFileName: ctx.String(outputFileFlag),
TimeFormat: ctx.String(timeFormatFlag),
OmitEmpty: ctx.Bool(omitEmptyFlag),
Alphabetical: ctx.Bool(alphabeticalFlag),
}

if ctx.Bool(stdoutFlag) {
Expand Down
2 changes: 2 additions & 0 deletions gen/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Config struct {
OutputFileName string
TimeFormat string
OmitEmpty bool
Alphabetical bool
}

func (c *Config) toJensharedConfig() *jenshared.Config {
Expand All @@ -39,6 +40,7 @@ func (c *Config) toJensharedConfig() *jenshared.Config {
OutputDirectory: dir,
TimeFormat: c.getTimeFormat(),
OmitEmpty: c.OmitEmpty,
Alphabetical: c.Alphabetical,
Debugger: c.Debugger,
}
}
Expand Down
34 changes: 26 additions & 8 deletions jenshared/addStructs.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,53 @@
package jenshared

import (
"sort"

"github.com/dave/jennifer/jen"
)

func addStructs(f *jen.File, itemMap TypeItemsMap) {
for name, items := range itemMap {
f.Add(createStruct(name, items))
func addStructs(f *jen.File, itemMap TypeItemsMap, config *Config) {
keys := make([]string, 0, len(itemMap))
for key := range itemMap {
keys = append(keys, key)
}

if config.Alphabetical {
sort.Strings(keys)
}

for _, key := range keys {
f.Add(createStruct(key, itemMap[key], config))
f.Line()
}
}

func addStruct(f *jen.File, name string, items TypeItems) {
f.Add(createStruct(name, items))
func addStruct(f *jen.File, name string, items TypeItems, config *Config) {
f.Add(createStruct(name, items, config))
}

func createStruct(name string, items TypeItems) *jen.Statement {
func createStruct(name string, items TypeItems, config *Config) *jen.Statement {

if len(items) == 1 && name == items[0].Name {
return jen.Type().Id(name).Id(items[0].Type)
}

structItems := createStructItems(items)
structItems := createStructItems(items, config)

return jen.Type().Id(name).Struct(structItems...)
}

func createStructItems(items TypeItems) []jen.Code {
func createStructItems(items TypeItems, config *Config) []jen.Code {
structItems := make([]jen.Code, 0)

if config.Alphabetical {
sort.Slice(items, func(i, ii int) bool {
return items[i].Title() < items[ii].Title()
})
}

for _, item := range items {
item.OmitEmpty = config.OmitEmpty
structItems = append(structItems, createStructItem(item))
}

Expand Down
12 changes: 6 additions & 6 deletions jenshared/addStructsFromJSON.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

func addStructsFromJSON(f *jen.File, data interface{}, config *Config) {
typeItemsMap := createTypeItemsMapFromJSON(data, config)
addStructs(f, typeItemsMap)
addStructs(f, typeItemsMap, config)
}

func createTypeItemsMapFromJSON(data interface{}, config *Config) TypeItemsMap {
Expand All @@ -23,7 +23,7 @@ func createTypeItemsMapFromJSON(data interface{}, config *Config) TypeItemsMap {
func parseInterface(items TypeItemsMap, data interface{}, config *Config) TypeItemsMap {
switch concreteVal := data.(type) {
case bool, float64, string:
items[config.RootName] = TypeItems{{Name: config.RootName, Type: inferDataType(concreteVal, config), OmitEmpty: config.OmitEmpty}}
items[config.RootName] = TypeItems{{Name: config.RootName, Type: inferDataType(concreteVal, config)}}
case map[string]interface{}:
parseMap(items, concreteVal, config.RootName, config)
case []interface{}:
Expand All @@ -37,10 +37,10 @@ func diveTopLevelArray(items TypeItemsMap, data []interface{}, config *Config, a
if len(data) > 0 {
switch firstVal := data[0].(type) {
case bool, float64, string:
items[config.RootName] = TypeItems{{Name: config.RootName, Type: fmt.Sprintf("%s%s", acc, inferDataType(firstVal, config)), OmitEmpty: config.OmitEmpty}}
items[config.RootName] = TypeItems{{Name: config.RootName, Type: fmt.Sprintf("%s%s", acc, inferDataType(firstVal, config))}}
case map[string]interface{}:
arrTitle := fmt.Sprintf("%sArray", config.RootName)
items[arrTitle] = TypeItems{{Name: arrTitle, Type: fmt.Sprintf("%s%s", acc, config.RootName), OmitEmpty: config.OmitEmpty}}
items[arrTitle] = TypeItems{{Name: arrTitle, Type: fmt.Sprintf("%s%s", acc, config.RootName)}}
parseMap(items, firstVal, config.RootName, config)

case []interface{}:
Expand All @@ -60,10 +60,10 @@ func parseMap(items TypeItemsMap, data map[string]interface{}, parent string, co
items[parent] = append(items[parent], TypeItem{Name: key, Type: title})
parseMap(items, concreteVal, title, config)
case []interface{}:
items[parent] = append(items[parent], TypeItem{Name: key, Type: fmt.Sprintf("[]%s", title), OmitEmpty: config.OmitEmpty})
items[parent] = append(items[parent], TypeItem{Name: key, Type: fmt.Sprintf("[]%s", title)})
parseFirstIndexArray(items, concreteVal, title, config)
default:
items[parent] = append(items[parent], TypeItem{Name: key, Type: inferDataType(concreteVal, config), OmitEmpty: config.OmitEmpty})
items[parent] = append(items[parent], TypeItem{Name: key, Type: inferDataType(concreteVal, config)})
}
}
return items
Expand Down
1 change: 1 addition & 0 deletions jenshared/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Config struct {
OutputDirectory string
TimeFormat string
OmitEmpty bool
Alphabetical bool
Debugger *log.Logger
}

Expand Down

0 comments on commit c9145c7

Please sign in to comment.