jsonstruct

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2023 License: BSD-3-Clause Imports: 14 Imported by: 0

README

jsonstruct

Test and lint Go Reference Go Report Card

jsonstruct is both a library and a command line tool to produce Go structs based on example JSON text. I just refactored this pretty heavily, so there may still be bugs. It uses gofumpt to format its output.

Installation

go install github.com/cneill/jsonstruct/cmd/jsonstruct@latest

Usage

NAME:
   jsonstruct - generate Go structs for JSON values

USAGE:
   jsonstruct [global options] command [command options] [FILE]...

DESCRIPTION:
   You can either pass in files as args or JSON in STDIN. Results are printed to STDOUT.

COMMANDS:
   http     run a web app to generate structs in the browser
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --name value, -n value    override the default name derived from filename
   --value-comments, -c      add a comment to struct fields with the example value(s) (default: false)
   --sort-fields, -s         sort the fields in alphabetical order; default behavior is to mirror input (default: false)
   --inline-structs, -i      use inline structs instead of creating different types for each object (default: false)
   --print-filenames, -f     print the filename above the structs defined within (default: false)
   --out-file FILE, -o FILE  write the results to FILE
   --debug, -d               enable debug logs (default: false)
   --help, -h                show help

Examples

Webapp

http-screenshot

The http command allows you to run a webapp to generate these structs in the browser.

JSON object

Input:

{
    "currency": "value",
    "amount": 4.267,
    "map": {
        "something": "nothing",
        "this": true
    },
    "array": [
        1,
        2,
        3,
        4
    ],
    "string_array": [
        "string",
        "string2",
        "string3"
    ],
    "CamelKey": "blah",
    "blahBlahBlah": "blah",
    "structs": [
        {
            "stuff": "stuff"
        },
        {
            "stuff": "stuff2"
        },
        {
            "stuff": "stuff3",
            "differentStuff": "differentStuff"
        }
    ],
    "nested_numbers": [
        [1, 2, 3],
        [2, 3, 4],
        [3, 4, 5]
    ],
    "nothing": null
}

Output:

type Stdin1 struct {
        Currency      string   `json:"currency"`
        Amount        float64  `json:"amount"`
        Map           *Map     `json:"map"`
        Array         []int64  `json:"array"`
        StringArray   []string `json:"string_array"`
        CamelKey      string
        BlahBlahBlah  string           `json:"blahBlahBlah"`
        Structs       []*Structs       `json:"structs"`
        NestedNumbers [][]int64        `json:"nested_numbers"`
        Nothing       *json.RawMessage `json:"nothing"`
}

type Map struct {
        Something string `json:"something"`
        This      bool   `json:"this"`
}

type Structs struct {
        Stuff          string `json:"stuff"`
        DifferentStuff string `json:"differentStuff,omitempty"`
}
JSON array of objects
[
    {
        "stuff": "stuff"
    },
    {
        "stuff": "stuff2"
    },
    {
        "stuff": "stuff3",
        "differentStuff": "differentStuff"
    },
    {
        "stuff": 1,
        "differentStuff": "blah"
    }
]
type Stdin1 struct {
        Stuff          *json.RawMessage `json:"stuff"`
        DifferentStuff string           `json:"differentStuff,omitempty"`
}
Value comments (-c)

Input:

{
  "test_bool": true,
  "test_int64": 1234,
  "test_float64": 1234.0,
  "test_string": "test",
  "test_array_of_bool": [true, false, true],
  "test_array_of_int64": [1, 2, 3, 4],
  "test_array_of_float64": [1.0, 2.0, 3.0, 4.0],
  "test_array_of_string": ["test1", "test2", "test3"],
  "test_struct": {
    "test_string": "test",
    "test_array_of_string": ["test1", "test2", "test3"]
  },
  "test_array_of_struct": [
    {
      "test_string": "test1",
      "test_optional_string": "test1"
    },
    {
      "test_string": "test2",
      "test_optional_string": "test2"
    },
    {
      "test_string": "test3"
    },
    {
      "test_string": "test4"
    }
  ],
  "test_garbage_array": [1, "1", 1.0],
  "terrible-name.for_a.key": "test"
}

Output:

type Stdin1 struct {
        TestBool            bool                 `json:"test_bool"`             // Example: true
        TestInt64           int64                `json:"test_int64"`            // Example: 1234
        TestFloat64         float64              `json:"test_float64"`          // Example: 1234.000
        TestString          string               `json:"test_string"`           // Example: "test"
        TestArrayOfBool     []bool               `json:"test_array_of_bool"`    // Example: [true, false, true]
        TestArrayOfInt64    []int64              `json:"test_array_of_int64"`   // Example: [1, 2, 3, 4]
        TestArrayOfFloat64  []float64            `json:"test_array_of_float64"` // Example: [1.000, 2.000, 3.000, 4.000]
        TestArrayOfString   []string             `json:"test_array_of_string"`  // Example: ["test1", "test2", "test3"]
        TestStruct          *TestStruct          `json:"test_struct"`
        TestArrayOfStruct   []*TestArrayOfStruct `json:"test_array_of_struct"`
        TestGarbageArray    []*json.RawMessage   `json:"test_garbage_array"`
        TerribleNameForAKey string               `json:"terrible-name.for_a.key"` // Example: "test"
}

type TestStruct struct {
        TestString        string   `json:"test_string"`          // Example: "test"
        TestArrayOfString []string `json:"test_array_of_string"` // Example: ["test1", "test2", "test3"]
}

type TestArrayOfStruct struct {
        TestString         string `json:"test_string"`                    // Example: "test1"
        TestOptionalString string `json:"test_optional_string,omitempty"` // Example: "test1"
}
Inline struct definitions (-i)

Input:

{
  "test_struct": {
    "test_string": "test",
    "test_array_of_string": ["test1", "test2", "test3"]
  },
  "test_array_of_struct": [
    {
      "test_string": "test1",
      "test_optional_string": "test1"
    },
    {
      "test_string": "test2",
      "test_optional_string": "test2"
    },
    {
      "test_string": "test3"
    },
    {
      "test_string": "test4"
    }
  ]
}

Output:

type Stdin1 struct {
        TestStruct struct {
                TestString        string   `json:"test_string"`
                TestArrayOfString []string `json:"test_array_of_string"`
        } `json:"test_struct"`
        TestArrayOfStruct []struct {
                TestString         string `json:"test_string"`
                TestOptionalString string `json:"test_optional_string,omitempty"`
        } `json:"test_array_of_struct"`
}

Notes

  • When an array of JSON objects is detected, any keys that are provided in some objects but not others will get the ,omitempty flag
  • When the same field is detected in multiple objects in a JSON array with different value types, the Go type will be *json.RawMessage, which will contain the raw bytes of the field to allow for different types
  • Defaults to a *json.RawMessage type when:
    • JSON null is provided
    • There are multiple types in e.g. an array
    • There is an empty array
  • Can take input from either files passed in as CLI args or STDIN. Can take a stream of objects / arrays of objects.

TODO

  • De-duplicate structs that are created more than once by multiple instances in the example JSON file
  • Handle plural names for slice types

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CommonInitialisms = map[string]bool{
	"ACL":   true,
	"API":   true,
	"ASCII": true,
	"CPU":   true,
	"CSS":   true,
	"DNS":   true,
	"EOF":   true,
	"GUID":  true,
	"HTML":  true,
	"HTTP":  true,
	"HTTPS": true,
	"ID":    true,
	"IP":    true,
	"JSON":  true,
	"LHS":   true,
	"QPS":   true,
	"RAM":   true,
	"RHS":   true,
	"RPC":   true,
	"SLA":   true,
	"SMTP":  true,
	"SQL":   true,
	"SSH":   true,
	"TCP":   true,
	"TLS":   true,
	"TTL":   true,
	"UDP":   true,
	"UI":    true,
	"UID":   true,
	"UUID":  true,
	"URI":   true,
	"URL":   true,
	"UTF8":  true,
	"VM":    true,
	"XML":   true,
	"XMPP":  true,
	"XSRF":  true,
	"XSS":   true,
}

CommonInitialisms contains the words that are recognized by "go lint" as initials needing capitalization.

View Source
var ErrOverflow = errors.New("provided number was too large")

Functions

func GetFileGoName

func GetFileGoName(filePath string) string

func GetGoName

func GetGoName(input string) string

GetGoName takes in a field name or file name and returns a "normalized" (CamelCase) string suitable for use as a Go variable name.

Types

type Field

type Field struct {
	// contains filtered or unexported fields
}

Field represents a single struct field.

func NewField

func NewField() *Field

func (Field) Comment

func (f Field) Comment() string

Comment returns the string used for example value comments.

func (Field) Equals

func (f Field) Equals(input *Field) bool

Equals returns true if two Fields share an original name, Go name, and type - does not compare values!

func (Field) GetSliceStruct

func (f Field) GetSliceStruct() *JSONStruct

func (Field) GetStruct

func (f Field) GetStruct() *JSONStruct

GetStruct gets a the JSONStruct in RawValue if f is a struct or slice of struct, otherwise returns nil.

func (Field) IsSlice

func (f Field) IsSlice() bool

IsSlice returns true if RawValue is of kind slice.

func (Field) IsStruct

func (f Field) IsStruct() bool

IsStruct returns true if RawValue is either a struct or a pointer to a struct.

func (Field) IsStructSlice

func (f Field) IsStructSlice() bool

func (Field) Name

func (f Field) Name() string

Name returns the name of this field as it will be rendered in the final struct.

func (Field) OriginalName

func (f Field) OriginalName() string

func (*Field) SetJSONRaw

func (f *Field) SetJSONRaw() *Field

func (*Field) SetName

func (f *Field) SetName(originalName string) *Field

func (*Field) SetOptional

func (f *Field) SetOptional() *Field

func (*Field) SetValue

func (f *Field) SetValue(value any) *Field

func (Field) SimpleSliceValues

func (f Field) SimpleSliceValues() []string

SimpleSliceValues returns a slice of strings with the values of simple slice Fields ([]int64, []float64, []bool, []string). If it doesn't recognize the Field as one of these, it returns an empty slice.

func (Field) SliceType

func (f Field) SliceType() string

SliceType returns the type of the slice this field represents.

func (Field) Tag

func (f Field) Tag() string

Tag returns the JSON tag as it will be rendered in the final struct.

func (Field) Type

func (f Field) Type() string

Type returns the type of the field as it will be rendered in the final struct.

func (Field) Value

func (f Field) Value() string

Value returns the string version of RawValue.

type Fields

type Fields []*Field

Fields is a convenience type for a slice of Field structs.

func (Fields) SortAlphabetically

func (f Fields) SortAlphabetically()

type Formatter

type Formatter struct {
	*FormatterOptions
}

Formatter prints out the contents of JSONStructs based on its configuration.

func NewFormatter

func NewFormatter(opts *FormatterOptions) (*Formatter, error)

NewFormatter returns an initialized Formatter.

func (*Formatter) FormatStructs

func (f *Formatter) FormatStructs(inputs ...*JSONStruct) (string, error)

type FormatterOptions

type FormatterOptions struct {
	// SortFields returns fields in alphabetically sorted order.
	SortFields bool

	// ValueComments annotates the produced structs with "Example" comments including the values originally passed in
	// for this field.
	ValueComments bool

	// InlineStructs causes objects within the main object to be rendered inline rather than getting their own types.
	InlineStructs bool
}

FormatterOptions defines how the Formatter will produce its output.

func (*FormatterOptions) OK

func (f *FormatterOptions) OK() error

OK ensures that the options passed in are valid.

type JSONStruct

type JSONStruct struct {
	// contains filtered or unexported fields
}

JSONStruct contains the raw information about a JSON object to be rendered as a Go struct.

func New

func New() *JSONStruct

NewJSONStruct returns an initialized JSONStruct.

func (*JSONStruct) AddFields

func (j *JSONStruct) AddFields(fields ...*Field) *JSONStruct

AddFields appends Field objects to the JSONStruct.

func (*JSONStruct) Fields

func (j *JSONStruct) Fields() Fields

func (*JSONStruct) Name

func (j *JSONStruct) Name() string

func (*JSONStruct) NestLevel

func (j *JSONStruct) NestLevel() int

func (*JSONStruct) SetInSlice

func (j *JSONStruct) SetInSlice() *JSONStruct

func (*JSONStruct) SetName

func (j *JSONStruct) SetName(name string) *JSONStruct

SetName sets the name to be used as a type for the JSONStruct.

func (*JSONStruct) SetNestLevel

func (j *JSONStruct) SetNestLevel(i int) *JSONStruct

AddInlineLevels recursively sets the inlineLevel value for this JSONStruct, as well as its struct fields.

type JSONStructs

type JSONStructs []*JSONStruct

JSONStructs is a convenience type for a slice of JSONStruct structs.

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

func NewParser

func NewParser(input io.Reader, logger *slog.Logger) *Parser

func (*Parser) Start

func (p *Parser) Start() (JSONStructs, error)

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL