Skip to content

Commit

Permalink
Merge pull request #18 from twpayne/next
Browse files Browse the repository at this point in the history
Multiple fixes and improvements
  • Loading branch information
twpayne committed Mar 6, 2024
2 parents 35f8c60 + 002ce4d commit 2b88864
Show file tree
Hide file tree
Showing 12 changed files with 239 additions and 185 deletions.
18 changes: 13 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,26 @@ on:
- v*
jobs:
test:
strategy:
fail-fast: false
matrix:
go-version:
- stable
- oldstable
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
with:
go-version: ${{ matrix.go-version }}
- name: build
run: go build ./...
- name: test
run: go test ./...
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804
with:
version: v1.52.2
version: v1.56.2
10 changes: 9 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ linters:
- containedctx
- contextcheck
- decorder
- depguard
- dogsled
- dupl
- dupword
Expand Down Expand Up @@ -73,6 +72,7 @@ linters:
- whitespace
disable:
- cyclop
- depguard
- exhaustruct
- forbidigo
- funlen
Expand All @@ -95,6 +95,14 @@ linters:
- wsl

linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/twpayne/go-jsonstruct)
gofumpt:
extra-rules: true
module-path: github.com/twpayne/go-jsonstruct
goimports:
local-prefixes: github.com/twpayne/go-jsonstruct

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ which you can try by running
echo '{"nested":{"bar":true,"foo":"baz"}}' \
'{"nested":{"bar":false,"foo":null}}' \
'{"nested":{"bar":true,"foo":""}}' \
| gojsonstruct -packagename mypackage -typename MyType
| gojsonstruct --package-name mypackage --typename MyType
```

generates the output
Expand Down Expand Up @@ -158,7 +158,7 @@ file with one JSON object per line in `objects.json` you can run:

To learn about more about the available options, run:

gojsonstruct -help
gojsonstruct --help

## What are go-jsonstruct's key features?

Expand Down
43 changes: 22 additions & 21 deletions cmd/gojsonstruct/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ package main

import (
"compress/gzip"
"flag"
"fmt"
"io"
"os"
"strings"

"github.com/spf13/pflag"

"github.com/twpayne/go-jsonstruct/v2"
)

var (
abbreviations = flag.String("abbreviations", "", "comma-separated list of extra abbreviations")
format = flag.String("format", "json", "format (json or yaml)")
uncompress = flag.Bool("z", false, "decompress input with gzip")
omitempty = flag.String("omitempty", "auto", "generate omitempty (never, always, or auto)")
packageComment = flag.String("packagecomment", "", "package comment")
packageName = flag.String("packagename", "main", "package name")
skipUnparseableProperties = flag.Bool("skipunparseableproperties", true, "skip unparseable properties")
structTagName = flag.String("structtagname", "", "struct tag name")
typeComment = flag.String("typecomment", "", "type comment")
typeName = flag.String("typename", "T", "type name")
intType = flag.String("inttype", "", "integer type")
useJSONNumber = flag.Bool("usejsonnumber", false, "use json.Number")
goFormat = flag.Bool("goformat", true, "format generated Go code")
output = flag.String("o", "", "output filename")
abbreviations = pflag.String("abbreviations", "", "comma-separated list of extra abbreviations")
format = pflag.String("format", "json", "format (json or yaml)")
decompress = pflag.Bool("z", false, "decompress input with gzip")
omitempty = pflag.String("omitempty", "auto", "generate omitempty (never, always, or auto)")
packageComment = pflag.String("package-comment", "", "package comment")
packageName = pflag.String("package-name", "main", "package name")
skipUnparsableProperties = pflag.Bool("skip-unparsable-properties", true, "skip unparsable properties")
structTagName = pflag.String("struct-tag-name", "", "struct tag name")
typeComment = pflag.String("type-comment", "", "type comment")
typeName = pflag.String("typename", "T", "type name")
intType = pflag.String("int-type", "", "integer type")
useJSONNumber = pflag.Bool("use-json-number", false, "use json.Number")
goFormat = pflag.Bool("go-format", true, "format generated Go code")
output = pflag.String("o", "", "output filename")

omitEmptyOption = map[string]jsonstruct.OmitEmptyOption{
"never": jsonstruct.OmitEmptyNever,
Expand All @@ -35,11 +36,11 @@ var (
)

func run() error {
flag.Parse()
pflag.Parse()

options := []jsonstruct.GeneratorOption{
jsonstruct.WithOmitEmpty(omitEmptyOption[*omitempty]),
jsonstruct.WithSkipUnparseableProperties(*skipUnparseableProperties),
jsonstruct.WithSkipUnparsableProperties(*skipUnparsableProperties),
jsonstruct.WithUseJSONNumber(*useJSONNumber),
jsonstruct.WithGoFormat(*goFormat),
}
Expand Down Expand Up @@ -70,9 +71,9 @@ func run() error {

generator := jsonstruct.NewGenerator(options...)

if flag.NArg() == 0 {
if pflag.NArg() == 0 {
var input io.Reader = os.Stdin
if *uncompress {
if *decompress {
var err error
input, err = gzip.NewReader(input)
if err != nil {
Expand All @@ -95,13 +96,13 @@ func run() error {
} else {
switch *format {
case "json":
for _, arg := range flag.Args() {
for _, arg := range pflag.Args() {
if err := generator.ObserveJSONFile(arg); err != nil {
return err
}
}
case "yaml":
for _, arg := range flag.Args() {
for _, arg := range pflag.Args() {
if err := generator.ObserveYAMLFile(arg); err != nil {
return err
}
Expand Down
88 changes: 42 additions & 46 deletions generator.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package jsonstruct

// FIXME move substructs to top level

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"go/format"
"io"
"maps"
"os"
"sort"
"strings"

"golang.org/x/exp/maps"
"gopkg.in/yaml.v3"
)

Expand All @@ -32,27 +29,27 @@ const (

// A Generator generates Go types from observed values.
type Generator struct {
abbreviations map[string]bool
exportNameFunc ExportNameFunc
exportRenames map[string]string
goFormat bool
imports map[string]struct{}
intType string
omitEmptyOption OmitEmptyOption
packageComment string
packageName string
skipUnparseableProperties bool
structTagNames []string
typeComment string
typeName string
useJSONNumber bool
value *value
abbreviations map[string]bool
exportNameFunc ExportNameFunc
exportRenames map[string]string
goFormat bool
imports map[string]struct{}
intType string
omitEmptyOption OmitEmptyOption
packageComment string
packageName string
skipUnparsableProperties bool
structTagNames []string
typeComment string
typeName string
useJSONNumber bool
value *value
}

// A GeneratorOption sets an option on a Generator.
type GeneratorOption func(*Generator)

// WithAbbreviations sets the abbreviatons.
// WithAbbreviations sets the abbreviations.
func WithAbbreviations(abbreviations ...string) GeneratorOption {
return func(g *Generator) {
g.abbreviations = make(map[string]bool)
Expand Down Expand Up @@ -122,11 +119,11 @@ func WithRenames(renames map[string]string) GeneratorOption {
}
}

// WithSkipUnparseableProperties sets whether unparseable properties should be
// WithSkipUnparsableProperties sets whether unparsable properties should be
// skipped.
func WithSkipUnparseableProperties(skipUnparseableProperties bool) GeneratorOption {
func WithSkipUnparsableProperties(skipUnparsableProperties bool) GeneratorOption {
return func(g *Generator) {
g.skipUnparseableProperties = skipUnparseableProperties
g.skipUnparsableProperties = skipUnparsableProperties
}
}

Expand Down Expand Up @@ -185,18 +182,18 @@ func WithUseJSONNumber(useJSONNumber bool) GeneratorOption {
// NewGenerator returns a new Generator with options.
func NewGenerator(options ...GeneratorOption) *Generator {
g := &Generator{
abbreviations: maps.Clone(defaultAbbreviations),
exportRenames: make(map[string]string),
goFormat: true,
imports: make(map[string]struct{}),
intType: "int",
omitEmptyOption: OmitEmptyAuto,
packageName: "main",
skipUnparseableProperties: true,
structTagNames: []string{"json"},
typeName: "T",
useJSONNumber: false,
value: &value{},
abbreviations: maps.Clone(defaultAbbreviations),
exportRenames: make(map[string]string),
goFormat: true,
imports: make(map[string]struct{}),
intType: "int",
omitEmptyOption: OmitEmptyAuto,
packageName: "main",
skipUnparsableProperties: true,
structTagNames: []string{"json"},
typeName: "T",
useJSONNumber: false,
value: &value{},
}
g.exportNameFunc = func(name string) string {
if rename, ok := g.exportRenames[name]; ok {
Expand All @@ -220,17 +217,16 @@ func (g *Generator) Generate() ([]byte, error) {
fmt.Fprintf(buffer, "package %s\n", g.packageName)
imports := maps.Clone(g.imports)
goType, _ := g.value.goType(0, &generateOptions{
exportNameFunc: g.exportNameFunc,
imports: imports,
intType: g.intType,
omitEmptyOption: g.omitEmptyOption,
skipUnparseableProperties: g.skipUnparseableProperties,
structTagNames: g.structTagNames,
useJSONNumber: g.useJSONNumber,
exportNameFunc: g.exportNameFunc,
imports: imports,
intType: g.intType,
omitEmptyOption: g.omitEmptyOption,
skipUnparsableProperties: g.skipUnparsableProperties,
structTagNames: g.structTagNames,
useJSONNumber: g.useJSONNumber,
})
if len(imports) > 0 {
importsSlice := maps.Keys(imports)
sort.Strings(importsSlice)
importsSlice := sortedKeys(imports)
fmt.Fprintf(buffer, "import (\n")
for _, _import := range importsSlice {
fmt.Fprintf(buffer, "\"%s\"\n", _import)
Expand Down Expand Up @@ -307,7 +303,7 @@ func (g *Generator) ObserveYAMLFile(filename string) error {
return g.ObserveYAMLReader(file)
}

// isUnparseableProperty returns true if key cannot be parsed by encoding/json.
func isUnparseableProperty(key string) bool {
// isUnparsableProperty returns true if key cannot be parsed by encoding/json.
func isUnparsableProperty(key string) bool {
return strings.ContainsAny(key, ` ",`)
}
Loading

0 comments on commit 2b88864

Please sign in to comment.