Skip to content

Commit

Permalink
Merge pull request #90 from invopop/require-override
Browse files Browse the repository at this point in the history
'require' in jsonschema tags will always override ',omitempty'
  • Loading branch information
samlown committed Sep 6, 2023
2 parents 9f28aff + ed817e0 commit e63dc34
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 99 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v2
- uses: actions/setup-go@v4
with:
go-version: "1.17"
cache: false

- name: Lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.45
- name: Check out code
uses: actions/checkout@v3

- name: Lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.51
71 changes: 23 additions & 48 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,26 @@ output:
print-issued-lines: false

linters:
enable-all: true
disable:
- maligned
- megacheck
- lll
- typecheck # `go build` catches this, and it doesn't currently work with Go 1.11 modules
- goimports # horrendously slow with go modules :(
- dupl # has never been actually useful
- gochecknoglobals
- gochecknoinits
- interfacer # author deprecated it because it provides bad suggestions
- funlen
- whitespace
- godox
- wsl
- dogsled
- gomnd
- gocognit
enable:
- gocyclo
- scopelint
- godot
- nestif
- testpackage
- goerr113
- gci
- gofumpt
- exhaustivestruct
- nlreturn
- forbidigo
- cyclop
- paralleltest
- ifshort # so annoying
- golint
- tagliatelle
- forcetypeassert
- wrapcheck
- gocritic
- goconst
- dupl
- unconvert
- goimports
- unused
- vetshadow
- nakedret
- errcheck
- revive
- structcheck
- stylecheck
- exhaustive
- varnamelen
- ineffassign
- goconst
- vet
- unparam
- gofmt

linters-settings:
govet:
vet:
check-shadowing: true
use-installed-packages: true
dupl:
Expand All @@ -68,22 +44,21 @@ linters-settings:
disabled-checks:
- ifElseChain


issues:
max-per-linter: 0
max-same: 0
exclude-use-default: false
exclude:
# Captured by errcheck.
- '^(G104|G204):'
- "^(G104|G204):"
# Very commonly not checked.
- 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*Print(f|ln|)|os\.(Un)?Setenv). is not checked'
# Weird error only seen on Kochiku...
- 'internal error: no range for'
- "internal error: no range for"
- 'exported method `.*\.(MarshalJSON|UnmarshalJSON|URN|Payload|GoString|Close|Provides|Requires|ExcludeFromHash|MarshalText|UnmarshalText|Description|Check|Poll|Severity)` should have comment or be unexported'
- 'composite literal uses unkeyed fields'
- "composite literal uses unkeyed fields"
- 'declaration of "err" shadows declaration'
- 'by other packages, and that stutters'
- 'Potential file inclusion via variable'
- 'at least one file in a package should have a package comment'
- 'bad syntax for struct tag pair'
- "by other packages, and that stutters"
- "Potential file inclusion via variable"
- "at least one file in a package should have a package comment"
- "bad syntax for struct tag pair"
2 changes: 2 additions & 0 deletions fixtures/allow_additional_props.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
2 changes: 2 additions & 0 deletions fixtures/defaults_expanded_toplevel.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
2 changes: 2 additions & 0 deletions fixtures/ignore_type.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
2 changes: 2 additions & 0 deletions fixtures/no_reference.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
2 changes: 2 additions & 0 deletions fixtures/no_reference_anchor.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
36 changes: 18 additions & 18 deletions fixtures/schema_with_expression.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/invopop/jsonschema/expression",
"$ref": "#/$defs/Expression",
"$defs": {
"Expression": {
"properties": {
"value": {
"type": "integer",
"foo": "bar=='baz'"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"value"
]
}
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/invopop/jsonschema/expression",
"$ref": "#/$defs/Expression",
"$defs": {
"Expression": {
"properties": {
"value": {
"type": "integer",
"foo": "bar=='baz'"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"value"
]
}
}
}
}
2 changes: 2 additions & 0 deletions fixtures/test_user.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
2 changes: 2 additions & 0 deletions fixtures/test_user_assign_anchor.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@
"name",
"password",
"TestFlag",
"photo",
"photo2",
"age",
"email",
"uuid",
Expand Down
40 changes: 20 additions & 20 deletions reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ func (t *Schema) structKeywordsFromTags(f reflect.StructField, parent *Schema, p
}

// read struct tags for generic keyworks
func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName string) {
func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName string) { //nolint:gocyclo
for _, tag := range tags {
nameValue := strings.Split(tag, "=")
if len(nameValue) == 2 {
Expand Down Expand Up @@ -795,7 +795,6 @@ func (t *Schema) stringKeywords(tags []string) {
switch val {
case "date-time", "email", "hostname", "ipv4", "ipv6", "uri", "uuid":
t.Format = val
break
}
case "readOnly":
i, _ := strconv.ParseBool(val)
Expand Down Expand Up @@ -943,29 +942,29 @@ func (t *Schema) setExtra(key, val string) {
}
}

func requiredFromJSONTags(tags []string) bool {
func requiredFromJSONTags(tags []string, val *bool) {
if ignoredByJSONTags(tags) {
return false
return
}

for _, tag := range tags[1:] {
if tag == "omitempty" {
return false
*val = false
return
}
}
return true
*val = true
}

func requiredFromJSONSchemaTags(tags []string) bool {
func requiredFromJSONSchemaTags(tags []string, val *bool) {
if ignoredByJSONSchemaTags(tags) {
return false
return
}
for _, tag := range tags {
if tag == "required" {
return true
*val = true
}
}
return false
}

func nullableFromJSONSchemaTags(tags []string) bool {
Expand Down Expand Up @@ -1001,10 +1000,11 @@ func (r *Reflector) reflectFieldName(f reflect.StructField) (string, bool, bool,
return "", false, false, false
}

required := requiredFromJSONTags(jsonTags)
if r.RequiredFromJSONSchemaTags {
required = requiredFromJSONSchemaTags(schemaTags)
var required bool
if !r.RequiredFromJSONSchemaTags {
requiredFromJSONTags(jsonTags, &required)
}
requiredFromJSONSchemaTags(schemaTags, &required)

nullable := nullableFromJSONSchemaTags(schemaTags)

Expand Down Expand Up @@ -1044,29 +1044,29 @@ func (t *Schema) UnmarshalJSON(data []byte) error {
*t = *FalseSchema
return nil
}
type Schema_ Schema
type SchemaAlt Schema
aux := &struct {
*Schema_
*SchemaAlt
}{
Schema_: (*Schema_)(t),
SchemaAlt: (*SchemaAlt)(t),
}
return json.Unmarshal(data, aux)
}

// MarshalJSON is used to serialize a schema object or boolean.
func (t *Schema) MarshalJSON() ([]byte, error) {
if t.boolean != nil {
if *t.boolean {
return []byte("true"), nil
} else {
return []byte("false"), nil
}
return []byte("false"), nil
}
if reflect.DeepEqual(&Schema{}, t) {
// Don't bother returning empty schemas
return []byte("true"), nil
}
type Schema_ Schema
b, err := json.Marshal((*Schema_)(t))
type SchemaAlt Schema
b, err := json.Marshal((*SchemaAlt)(t))
if err != nil {
return nil, err
}
Expand Down
14 changes: 7 additions & 7 deletions reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net"
"net/url"
"os"
"path/filepath"
"reflect"
"strings"
Expand Down Expand Up @@ -34,13 +34,13 @@ type SomeBaseType struct {
// The jsonschema required tag is nonsensical for private and ignored properties.
// Their presence here tests that the fields *will not* be required in the output
// schema, even if they are tagged required.
somePrivateBaseProperty string `jsonschema:"required"`
somePrivateBaseProperty string `jsonschema:"required"` //nolint:unused
SomeIgnoredBaseProperty string `json:"-" jsonschema:"required"`
SomeSchemaIgnoredProperty string `jsonschema:"-,required"`
Grandfather GrandfatherType `json:"grand"`

SomeUntaggedBaseProperty bool `jsonschema:"required"`
someUnexportedUntaggedBaseProperty bool
someUnexportedUntaggedBaseProperty bool //nolint:unused
}

type MapType map[string]interface{}
Expand All @@ -49,7 +49,7 @@ type ArrayType []string

type nonExported struct {
PublicNonExported int
privateNonExported int
privateNonExported int // nolint:unused
}

type ProtoEnum int32
Expand Down Expand Up @@ -492,19 +492,19 @@ func TestBaselineUnmarshal(t *testing.T) {

func compareSchemaOutput(t *testing.T, f string, r *Reflector, obj interface{}) {
t.Helper()
expectedJSON, err := ioutil.ReadFile(f)
expectedJSON, err := os.ReadFile(f)
require.NoError(t, err)

actualSchema := r.Reflect(obj)
actualJSON, _ := json.MarshalIndent(actualSchema, "", " ") //nolint:errchkjson

if *updateFixtures {
_ = ioutil.WriteFile(f, actualJSON, 0600)
_ = os.WriteFile(f, actualJSON, 0600)
}

if !assert.JSONEq(t, string(expectedJSON), string(actualJSON)) {
if *compareFixtures {
_ = ioutil.WriteFile(strings.TrimSuffix(f, ".json")+".out.json", actualJSON, 0600)
_ = os.WriteFile(strings.TrimSuffix(f, ".json")+".out.json", actualJSON, 0600)
}
}
}
Expand Down

0 comments on commit e63dc34

Please sign in to comment.