diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index a9871e6..34b30ed 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -13,12 +13,13 @@ jobs: uses: actions/checkout@v3 - name: build run: docker-compose run go-json + test: name: Test strategy: matrix: os: [ "ubuntu-latest", "macos-latest", "windows-latest" ] - go-version: [ "1.18", "1.19", "1.20" ] + go-version: [ "1.19", "1.20", "1.21" ] runs-on: ${{ matrix.os }} steps: - name: setup Go ${{ matrix.go-version }} @@ -35,6 +36,20 @@ jobs: GOGC: 1 - name: test with race detector run: go test -v -race ./... -count=1 + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + - name: setup Go + uses: actions/setup-go@v3 + with: + go-version: '1.21' + - name: lint + run: | + make lint bench: name: Benchmark runs-on: ubuntu-latest @@ -42,7 +57,7 @@ jobs: - name: setup Go uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21' - name: checkout ( feature ) uses: actions/checkout@v3 - name: run benchmark ( feature ) @@ -57,16 +72,17 @@ jobs: run: cd benchmarks && go test -bench GoJson | tee $HOME/old.txt - name: compare benchmark results run: benchstat $HOME/old.txt $HOME/new.txt + coverage: name: Coverage runs-on: ubuntu-latest steps: + - name: checkout + uses: actions/checkout@v3 - name: setup Go uses: actions/setup-go@v3 with: - go-version: '1.20' - - name: checkout - uses: actions/checkout@v3 + go-version: '1.21' - name: measure coverage run: make cover - uses: codecov/codecov-action@v3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index aa73ee3..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: lint -on: - push: - branches: - - master - pull_request: -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: golangci/golangci-lint-action@v3 - with: - version: v1.45.2 - args: --timeout=5m diff --git a/.golangci.yml b/.golangci.yml index 57ae5a5..977acca 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -56,6 +56,9 @@ linters: - cyclop - containedctx - revive + - nosnakecase + - exhaustruct + - depguard issues: exclude-rules: diff --git a/Makefile b/Makefile index 5bbfc4c..c030577 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ golangci-lint: | $(BIN_DIR) GOLANGCI_LINT_TMP_DIR=$$(mktemp -d); \ cd $$GOLANGCI_LINT_TMP_DIR; \ go mod init tmp; \ - GOBIN=$(BIN_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.48.0; \ + GOBIN=$(BIN_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.2; \ rm -rf $$GOLANGCI_LINT_TMP_DIR; \ } diff --git a/encode.go b/encode.go index 4bd899f..c517382 100644 --- a/encode.go +++ b/encode.go @@ -52,7 +52,7 @@ func (e *Encoder) EncodeContext(ctx context.Context, v interface{}, optFuncs ... rctx.Option.Flag |= encoder.ContextOption rctx.Option.Context = ctx - err := e.encodeWithOption(rctx, v, optFuncs...) + err := e.encodeWithOption(rctx, v, optFuncs...) //nolint: contextcheck encoder.ReleaseRuntimeContext(rctx) return err @@ -120,7 +120,7 @@ func marshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOption optFunc(rctx.Option) } - buf, err := encode(rctx, v) + buf, err := encode(rctx, v) //nolint: contextcheck if err != nil { encoder.ReleaseRuntimeContext(rctx) return nil, err diff --git a/go.mod b/go.mod index 58a1488..f5b57ff 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/goccy/go-json -go 1.12 +go 1.19 diff --git a/internal/cmd/generator/main.go b/internal/cmd/generator/main.go index 0712cd0..326f527 100644 --- a/internal/cmd/generator/main.go +++ b/internal/cmd/generator/main.go @@ -7,7 +7,7 @@ import ( "go/parser" "go/printer" "go/token" - "io/ioutil" + "os" "path/filepath" "runtime" "strings" @@ -273,11 +273,11 @@ func (t OpType) FieldToOmitEmptyField() OpType { if err != nil { return err } - return ioutil.WriteFile(path, buf, 0644) + return os.WriteFile(path, buf, 0644) } func generateVM() error { - file, err := ioutil.ReadFile("vm.go.tmpl") + file, err := os.ReadFile("vm.go.tmpl") if err != nil { return err } @@ -295,7 +295,7 @@ func generateVM() error { if err != nil { return err } - if err := ioutil.WriteFile(path, source, 0644); err != nil { + if err := os.WriteFile(path, source, 0644); err != nil { return err } } diff --git a/internal/decoder/unmarshal_text.go b/internal/decoder/unmarshal_text.go index 6d37993..d711d0f 100644 --- a/internal/decoder/unmarshal_text.go +++ b/internal/decoder/unmarshal_text.go @@ -147,7 +147,7 @@ func (d *unmarshalTextDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int return nil, 0, fmt.Errorf("json: unmarshal text decoder does not support decode path") } -func unquoteBytes(s []byte) (t []byte, ok bool) { +func unquoteBytes(s []byte) (t []byte, ok bool) { //nolint: nonamedreturns length := len(s) if length < 2 || s[0] != '"' || s[length-1] != '"' { return diff --git a/internal/encoder/string.go b/internal/encoder/string.go index e4152b2..4abb841 100644 --- a/internal/encoder/string.go +++ b/internal/encoder/string.go @@ -1,3 +1,27 @@ +// This files's string processing codes are inspired by https://github.com/segmentio/encoding. +// The license notation is as follows. +// +// # MIT License +// +// Copyright (c) 2019 Segment.io, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. package encoder import ( diff --git a/internal/runtime/rtype.go b/internal/runtime/rtype.go index 4db10de..37cfe35 100644 --- a/internal/runtime/rtype.go +++ b/internal/runtime/rtype.go @@ -252,7 +252,6 @@ func IfaceIndir(*Type) bool //go:noescape func RType2Type(t *Type) reflect.Type -//go:nolint structcheck type emptyInterface struct { _ *Type ptr unsafe.Pointer diff --git a/json.go b/json.go index 413cb20..fb18065 100644 --- a/json.go +++ b/json.go @@ -89,31 +89,31 @@ type UnmarshalerContext interface { // // Examples of struct field tags and their meanings: // -// // Field appears in JSON as key "myName". -// Field int `json:"myName"` +// // Field appears in JSON as key "myName". +// Field int `json:"myName"` // -// // Field appears in JSON as key "myName" and -// // the field is omitted from the object if its value is empty, -// // as defined above. -// Field int `json:"myName,omitempty"` +// // Field appears in JSON as key "myName" and +// // the field is omitted from the object if its value is empty, +// // as defined above. +// Field int `json:"myName,omitempty"` // -// // Field appears in JSON as key "Field" (the default), but -// // the field is skipped if empty. -// // Note the leading comma. -// Field int `json:",omitempty"` +// // Field appears in JSON as key "Field" (the default), but +// // the field is skipped if empty. +// // Note the leading comma. +// Field int `json:",omitempty"` // -// // Field is ignored by this package. -// Field int `json:"-"` +// // Field is ignored by this package. +// Field int `json:"-"` // -// // Field appears in JSON as key "-". -// Field int `json:"-,"` +// // Field appears in JSON as key "-". +// Field int `json:"-,"` // // The "string" option signals that a field is stored as JSON inside a // JSON-encoded string. It applies only to fields of string, floating point, // integer, or boolean types. This extra level of encoding is sometimes used // when communicating with JavaScript programs: // -// Int64String int64 `json:",string"` +// Int64String int64 `json:",string"` // // The key name will be used if it's a non-empty string consisting of // only Unicode letters, digits, and ASCII punctuation except quotation @@ -166,7 +166,6 @@ type UnmarshalerContext interface { // JSON cannot represent cyclic data structures and Marshal does not // handle them. Passing cyclic structures to Marshal will result in // an infinite recursion. -// func Marshal(v interface{}) ([]byte, error) { return MarshalWithOption(v) } @@ -264,14 +263,13 @@ func MarshalIndentWithOption(v interface{}, prefix, indent string, optFuncs ...E // // The JSON null value unmarshals into an interface, map, pointer, or slice // by setting that Go value to nil. Because null is often used in JSON to mean -// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// “not present,” unmarshaling a JSON null into any other Go type has no effect // on the value and produces no error. // // When unmarshaling quoted strings, invalid UTF-8 or // invalid UTF-16 surrogate pairs are not treated as an error. // Instead, they are replaced by the Unicode replacement // character U+FFFD. -// func Unmarshal(data []byte, v interface{}) error { return unmarshal(data, v) } @@ -299,7 +297,6 @@ func UnmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) // Number, for JSON numbers // string, for JSON string literals // nil, for JSON null -// type Token = json.Token // A Number represents a JSON number literal.