Skip to content

Commit 12095c3

Browse files
authored
Add support for subschemas (#99)
* feat: implement support for sub-schemas * fix: add guard against loading non-json files when reading references in schemas * feat: introduce basic allOf support * fix: handle struct slices prop merging for allOf types * feat: introduce basic anyOf support, fix default value issue. * fix: make anyOf properties of primitive types dump interface instead of first type * fix: reduce duplicate types * fix: furhter reduce duplicate types * chore: refactor cmp Opts utility * fix: add graceful handling of some edge cases in code generation * empty enum type name * missing unmarshal methods for map types * "Plain" type naming collisions * schema.Type new properties potential (de)serialization * chore: rename test files after rebase * chore: cleanup go deps * chore: fix go linting issues * chore: integrate new formatter changes after rebase * fix: set consistent var names in unmarshallers, introduce support for both yaml and json in validators * chore: remove dead code * fix: use '>' instead of '>=' to perform max length validation. * chore: remove 'two' constant * chore: disable gomnd linter * chore: update deps * chore: fix linting issues * fix: adapt additionalProperties tests after rebase * fix: adapt date tests after rebase * fix: adapt tests with required fields after rebase * fix: adapt remaining failing tests after rebase * fix: rename inconsistently-named tests * feat: commit go.work * chore: update go work * chore: align all golang versions to 1.22.9 * fix: correct conflict resolution mistakes after updating from main. * chore: refactor generator code, remove dead code. * fix: regenerate most go-generated code in tests, remove wrong guard in string validator * chore: remove useless file * fix: address linting issues. * fix: make anyOf and allOf work with refs * fix: add support for anyOf and allOf also on properties on the root type * feat: introduce ability to infer common root type in subschemas that don't specify it * chore: remove deprecated linters * fix: add receivers nolint to date and time types * fix: correct linting issues * fix: set ptr receiver in model * chore: add missing json tags to model * chore: refactor generateStructType to reduce cyclomatic complexity * chore: bump golangci-lint version * chore: tweak resolveRefs function * chore: tweak resolveRefs function * fix: add guard against setting alias types using the same name of the aliased one * chore: add tests combining allOf and anyOF * chore: fix linting issues * chore: ignore output/ folder * wip: resolving infinite recursion issue * chore: refactor cycle detection * feat: improve enter/exit subschema functions in nameScope to support nested subschemas * fix: set test assertions parameters in the right order * fix: add guards agains false cycle detections * fix: refine codegen for recursive subschemas * fix: correct linting issues * chore: rename tests
1 parent a84a84f commit 12095c3

File tree

119 files changed

+7598
-835
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+7598
-835
lines changed

.github/workflows/development.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- name: Download golangci-lint installer
2727
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh -o /tmp/install-golangci-lint.sh
2828
- name: Install golangci-lint
29-
run: sh /tmp/install-golangci-lint.sh -b /usr/local/bin v1.61.0
29+
run: sh /tmp/install-golangci-lint.sh -b /usr/local/bin v1.62.2
3030
- name: Lint Go files
3131
run: ./scripts/lint-golang.sh
3232
- name: Run tests

.rules/.golangci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ linters:
3434
- wastedassign
3535
# deprecated
3636
- exportloopref
37-
- gomnd
38-
- execinquery
3937
# unused
4038
- exhaustruct
4139
- forbidigo
40+
- mnd
41+
4242
linters-settings:
4343
decorder:
4444
disable-init-func-first-check: false

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SHELL := /bin/bash
99

1010
_DOCKER_FILELINT_IMAGE=cytopia/file-lint:latest-0.8
1111
_DOCKER_GOLANG_IMAGE=golang:1.23.7
12-
_DOCKER_GOLANGCI_LINT_IMAGE=golangci/golangci-lint:v1.61.0
12+
_DOCKER_GOLANGCI_LINT_IMAGE=golangci/golangci-lint:v1.62.2
1313
_DOCKER_HADOLINT_IMAGE=hadolint/hadolint:v2.12.0
1414
_DOCKER_JSONLINT_IMAGE=cytopia/jsonlint:1.6
1515
_DOCKER_MAKEFILELINT_IMAGE=cytopia/checkmake:latest-0.5

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ go 1.23.0
55
toolchain go1.23.7
66

77
require (
8+
dario.cat/mergo v1.0.0
89
github.com/davecgh/go-spew v1.1.1 // indirect
910
github.com/goccy/go-yaml v1.15.23
11+
github.com/google/go-cmp v0.6.0
1012
github.com/mitchellh/go-wordwrap v1.0.1
1113
github.com/pkg/errors v0.9.1
1214
github.com/sanity-io/litter v1.5.8
@@ -15,7 +17,7 @@ require (
1517
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
1618
)
1719

18-
require gopkg.in/yaml.v3 v3.0.1
20+
require gopkg.in/yaml.v3 v3.0.1 // indirect
1921

2022
require (
2123
github.com/inconshreveable/mousetrap v1.1.0 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
2+
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
13
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
24
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
46
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
57
github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo=
68
github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
9+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
10+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
711
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
812
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
913
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=

go.work

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
go 1.23.0
2+
3+
use (
4+
.
5+
./tests
6+
)

go.work.sum

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
github.com/atombender/go-jsonschema/tests/data v0.0.0-20231003003002-2b73c089a581/go.mod h1:kLoRQLRVy+GT9/PG2e3u31DPvDmtFEn7pX6FItvbqlA=
12
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
4+
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
35
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
46
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
57
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
8+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
69
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
10+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
711
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
812
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
913
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -21,20 +25,24 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
2125
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
2226
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
2327
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
28+
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
2429
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
2530
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
2631
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
32+
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
33+
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
2734
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
2835
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
2936
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
3037
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
3138
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
3239
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3340
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
41+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
42+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3443
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
3544
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
36-
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
37-
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
45+
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3846
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
3947
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
4048
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -45,9 +53,12 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
4553
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
4654
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
4755
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
56+
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
4857
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
4958
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
5059
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
60+
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
61+
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
5162
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
5263
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5364
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

internal/x/text/cases.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ func (c *Caser) Identifierize(s string) string {
5656
}
5757
}
5858

59+
if ident == "" {
60+
return "Undefined"
61+
}
62+
5963
return ident
6064
}
6165

pkg/cmputil/opts.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cmputil
2+
3+
import (
4+
"github.com/google/go-cmp/cmp"
5+
"github.com/google/go-cmp/cmp/cmpopts"
6+
)
7+
8+
func Opts(t ...any) []cmp.Option {
9+
opts := make([]cmp.Option, 0)
10+
11+
for _, v := range t {
12+
opts = append(opts, cmpopts.IgnoreUnexported(v), cmpopts.IgnoreFields(v, "Ref"), cmpopts.IgnoreFields(v, "AnyOf"))
13+
}
14+
15+
return opts
16+
}

pkg/codegen/model.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package codegen
22

33
import (
4+
"reflect"
45
"sort"
56
"strings"
67

@@ -39,8 +40,20 @@ type Package struct {
3940
Imports []Import
4041
}
4142

42-
func (p *Package) AddDecl(t Decl) {
43-
p.Decls = append(p.Decls, t)
43+
func (p *Package) AddDecl(d Decl) {
44+
if !p.hasDecl(d) {
45+
p.Decls = append(p.Decls, d)
46+
}
47+
}
48+
49+
func (p *Package) hasDecl(d Decl) bool {
50+
for _, pd := range p.Decls {
51+
if pd == d || reflect.DeepEqual(pd, d) {
52+
return true
53+
}
54+
}
55+
56+
return false
4457
}
4558

4659
func (p *Package) AddImport(qualifiedName, alias string) {
@@ -197,9 +210,10 @@ func (i *Import) Generate(out *Emitter) {
197210

198211
// TypeDecl is a "type <name> = <definition>".
199212
type TypeDecl struct {
200-
Name string
201-
Type Type
202-
Comment string
213+
Name string
214+
Type Type
215+
Comment string
216+
SchemaType *schemas.Type
203217
}
204218

205219
func (td *TypeDecl) GetName() string {
@@ -218,6 +232,16 @@ type Type interface {
218232
IsNillable() bool
219233
}
220234

235+
type AliasType struct {
236+
Decl
237+
Alias string
238+
Name string
239+
}
240+
241+
func (p AliasType) Generate(out *Emitter) {
242+
out.Printf("type %s = %s", p.Alias, p.Name)
243+
}
244+
221245
type PointerType struct {
222246
Type Type
223247
}
@@ -315,9 +339,10 @@ func (NullType) Generate(out *Emitter) {
315339
type StructType struct {
316340
Fields []StructField
317341
RequiredJSONFields []string
342+
DefaultValue interface{}
318343
}
319344

320-
func (StructType) IsNillable() bool { return false }
345+
func (*StructType) IsNillable() bool { return false }
321346

322347
func (s *StructType) AddField(f StructField) {
323348
s.Fields = append(s.Fields, f)

0 commit comments

Comments
 (0)