Skip to content

Commit

Permalink
Merge pull request #1 from cneill/new_master
Browse files Browse the repository at this point in the history
The rewrite!
  • Loading branch information
cneill authored Sep 13, 2023
2 parents 4bd1687 + 1560dad commit cadd72d
Show file tree
Hide file tree
Showing 26 changed files with 1,855 additions and 744 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: Cut release for tag
on:
push:
tags:
- '*'
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'

- name: Run goreleaser
uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31 changes: 31 additions & 0 deletions .github/workflows/test-and-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
name: Test and lint
on: [push]
jobs:
test-and-lint:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.21"

- name: Build
run: go build -v ./...

- name: Test
run: go test -v ./...

- name: FuzzParser
run: go test -v -fuzztime 60s -fuzz "FuzzParser"

- name: FuzzGetGoName
run: go test -v -fuzztime 60s -fuzz "FuzzGetGoName"

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
20 changes: 0 additions & 20 deletions .github/workflows/test.yaml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
cmd/jsonstruct/jsonstruct
testdata/
31 changes: 31 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
builds:
- id: main
goos:
- darwin
- linux
- windows
goarch:
- amd64
- arm64
env:
- CGO_ENABLED=0
ignore:
- goos: windows
goarch: arm64
archives:
- id: main
builds:
- main
format: tar.gz
checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
use: github-native
abbrev: 0
sort: asc
filters:
exclude:
- typo
179 changes: 156 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/cneill/jsonstruct.svg)](https://pkg.go.dev/github.com/cneill/jsonstruct)
[![Go Report Card](https://goreportcard.com/badge/github.com/cneill/jsonstruct)](https://goreportcard.com/report/github.com/cneill/jsonstruct)

`jsonstruct` is both a library and a command line tool to produce Go structs based on example JSON text. It's in the middle of
a refactor, so you probably don't want to rely on it too heavily right now.
`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`](https://github.com/mvdan/gofumpt) to
format its output.

## Installation

Expand All @@ -16,18 +17,34 @@ go install github.com/cneill/jsonstruct/cmd/jsonstruct@latest
## Usage

```
Usage of ./jsonstruct:
./jsonstruct [flags] [file name...]
NAME:
jsonstruct - generate Go structs for JSON values
Flags:
-value-comments
add a comment to struct fields with the example value(s)
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:
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)
--debug enable debug logs (default: false)
--help, -h show help
```

## Examples

### JSON object

**Input:**

```json
{
"currency": "value",
Expand Down Expand Up @@ -61,23 +78,29 @@ Flags:
"differentStuff": "differentStuff"
}
],
"nested_numbers": [
[1, 2, 3],
[2, 3, 4],
[3, 4, 5]
],
"nothing": null
}
```

The above JSON object Will produce this output:
**Output:**

```golang
type Test struct {
StringArray []string `json:"string_array"`
BlahBlahBlah string `json:"blahBlahBlah"`
Nothing string `json:"nothing"`
Currency string `json:"currency"`
Amount float64 `json:"amount"`
Map *Map `json:"map"`
Array []float64 `json:"array"`
CamelKey string `json:"CamelKey"`
Structs []*Structs `json:"structs"`
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 {
Expand Down Expand Up @@ -113,18 +136,128 @@ type Structs struct {
```

```golang
type ArrayTest struct {
Stuff *json.RawMessage `json:"stuff"`
DifferentStuff string `json:"differentStuff,omitempty"`
type Stdin1 struct {
Stuff *json.RawMessage `json:"stuff"`
DifferentStuff string `json:"differentStuff,omitempty"`
}
```

### Value comments (`-c`)

**Input:**

```json
{
"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:**

```golang
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:**

```json
{
"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:**

```golang
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
* Tries to detect `float64` and `int64`, but there's a bug where floats like `1.0` will be treated as
ints (floats like `1.2` will be correctly detected as such)
* 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
Expand Down
Loading

0 comments on commit cadd72d

Please sign in to comment.