diff --git a/go.mod b/go.mod index aa509d96296..7e677455cb5 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module go.k6.io/k6 -go 1.24.0 - -toolchain go1.24.9 +go 1.25 require ( buf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.36.10-20251006115534-cbd485bd5afd.1 @@ -14,7 +12,7 @@ require ( github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d github.com/evanw/esbuild v0.25.10 github.com/fatih/color v1.18.0 - github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 + github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 github.com/go-sourcemap/sourcemap v2.1.4+incompatible github.com/golang/protobuf v1.5.4 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index 91f36935a13..3591f306db9 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 h1:yE7argOs92u+sSCRgqqe6eF+cDaVhSPlioy1UkA0p/w= -github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s= +github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 h1:02WINGfSX5w0Mn+F28UyRoSt9uvMhKguwWMlOAh6U/0= +github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= diff --git a/vendor/github.com/go-json-experiment/json/README.md b/vendor/github.com/go-json-experiment/json/README.md index 10d0fb3c977..937c3980052 100644 --- a/vendor/github.com/go-json-experiment/json/README.md +++ b/vendor/github.com/go-json-experiment/json/README.md @@ -12,7 +12,7 @@ with the string "WARNING: " near the top of the commit message. It is your responsibility to inspect the list of commit changes when upgrading the module. Not all breaking changes will lead to build failures. -A [Discussion about including this package in Go as `encoding/json/v2`](https://github.com/golang/go/discussions/63397) has been started on the Go Github project on 2023-10-05. Please provide your feedback there. +A [proposal to include this module in Go as `encoding/json/v2` and `encoding/json/jsontext`](https://github.com/golang/go/issues/71497) has been started on the Go Github project on 2025-01-30. Please provide your feedback there. ## Goals and objectives @@ -159,7 +159,7 @@ This table shows an overview of the changes: | When unmarshaling, **an error does not occur** if the input JSON value contains objects with duplicate names. | When unmarshaling, **an error does occur** if the input JSON value contains objects with duplicate names. | [DuplicateNames](/v1/diff_test.go#:~:text=TestDuplicateNames) | | Unmarshaling a JSON null into a non-empty Go value **inconsistently clears the value or does nothing**. | Unmarshaling a JSON null into a non-empty Go value **always clears the value**. | [MergeNull](/v1/diff_test.go#:~:text=TestMergeNull) | | Unmarshaling a JSON value into a non-empty Go value **follows inconsistent and bizarre behavior**. | Unmarshaling a JSON value into a non-empty Go value **always merges if the input is an object, and otherwise replaces**. | [MergeComposite](/v1/diff_test.go#:~:text=TestMergeComposite) | -| A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` is represented as a **JSON string containing the formatted duration (e.g., "1h2m3.456s")**. | [TimeDurations](/v1/diff_test.go#:~:text=TestTimeDurations) | +| A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` has no default representation in v2 (see [#71631](https://golang.org/issue/71631)) and results in an error. | | | A Go struct with only unexported fields **can be serialized**. | A Go struct with only unexported fields **cannot be serialized**. | [EmptyStructs](/v1/diff_test.go#:~:text=TestEmptyStructs) | See [diff_test.go](/v1/diff_test.go) for details about every change. diff --git a/vendor/github.com/go-json-experiment/json/alias.go b/vendor/github.com/go-json-experiment/json/alias.go new file mode 100644 index 00000000000..e239118d85e --- /dev/null +++ b/vendor/github.com/go-json-experiment/json/alias.go @@ -0,0 +1,1008 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by alias_gen.go; DO NOT EDIT. + +//go:build goexperiment.jsonv2 && go1.25 + +// Package json implements semantic processing of JSON as specified in RFC 8259. +// JSON is a simple data interchange format that can represent +// primitive data types such as booleans, strings, and numbers, +// in addition to structured data types such as objects and arrays. +// +// [Marshal] and [Unmarshal] encode and decode Go values +// to/from JSON text contained within a []byte. +// [MarshalWrite] and [UnmarshalRead] operate on JSON text +// by writing to or reading from an [io.Writer] or [io.Reader]. +// [MarshalEncode] and [UnmarshalDecode] operate on JSON text +// by encoding to or decoding from a [jsontext.Encoder] or [jsontext.Decoder]. +// [Options] may be passed to each of the marshal or unmarshal functions +// to configure the semantic behavior of marshaling and unmarshaling +// (i.e., alter how JSON data is understood as Go data and vice versa). +// [jsontext.Options] may also be passed to the marshal or unmarshal functions +// to configure the syntactic behavior of encoding or decoding. +// +// The data types of JSON are mapped to/from the data types of Go based on +// the closest logical equivalent between the two type systems. For example, +// a JSON boolean corresponds with a Go bool, +// a JSON string corresponds with a Go string, +// a JSON number corresponds with a Go int, uint or float, +// a JSON array corresponds with a Go slice or array, and +// a JSON object corresponds with a Go struct or map. +// See the documentation on [Marshal] and [Unmarshal] for a comprehensive list +// of how the JSON and Go type systems correspond. +// +// Arbitrary Go types can customize their JSON representation by implementing +// [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom]. +// This provides authors of Go types with control over how their types are +// serialized as JSON. Alternatively, users can implement functions that match +// [MarshalFunc], [MarshalToFunc], [UnmarshalFunc], or [UnmarshalFromFunc] +// to specify the JSON representation for arbitrary types. +// This provides callers of JSON functionality with control over +// how any arbitrary type is serialized as JSON. +// +// # JSON Representation of Go structs +// +// A Go struct is naturally represented as a JSON object, +// where each Go struct field corresponds with a JSON object member. +// When marshaling, all Go struct fields are recursively encoded in depth-first +// order as JSON object members except those that are ignored or omitted. +// When unmarshaling, JSON object members are recursively decoded +// into the corresponding Go struct fields. +// Object members that do not match any struct fields, +// also known as “unknown members”, are ignored by default or rejected +// if [RejectUnknownMembers] is specified. +// +// The representation of each struct field can be customized in the +// "json" struct field tag, where the tag is a comma separated list of options. +// As a special case, if the entire tag is `json:"-"`, +// then the field is ignored with regard to its JSON representation. +// Some options also have equivalent behavior controlled by a caller-specified [Options]. +// Field-specified options take precedence over caller-specified options. +// +// The first option is the JSON object name override for the Go struct field. +// If the name is not specified, then the Go struct field name +// is used as the JSON object name. JSON names containing commas or quotes, +// or names identical to "" or "-", can be specified using +// a single-quoted string literal, where the syntax is identical to +// the Go grammar for a double-quoted string literal, +// but instead uses single quotes as the delimiters. +// By default, unmarshaling uses case-sensitive matching to identify +// the Go struct field associated with a JSON object name. +// +// After the name, the following tag options are supported: +// +// - omitzero: When marshaling, the "omitzero" option specifies that +// the struct field should be omitted if the field value is zero +// as determined by the "IsZero() bool" method if present, +// otherwise based on whether the field is the zero Go value. +// This option has no effect when unmarshaling. +// +// - omitempty: When marshaling, the "omitempty" option specifies that +// the struct field should be omitted if the field value would have been +// encoded as a JSON null, empty string, empty object, or empty array. +// This option has no effect when unmarshaling. +// +// - string: The "string" option specifies that [StringifyNumbers] +// be set when marshaling or unmarshaling a struct field value. +// This causes numeric types to be encoded as a JSON number +// within a JSON string, and to be decoded from a JSON string +// containing the JSON number without any surrounding whitespace. +// This extra level of encoding is often necessary since +// many JSON parsers cannot precisely represent 64-bit integers. +// +// - case: When unmarshaling, the "case" option specifies how +// JSON object names are matched with the JSON name for Go struct fields. +// The option is a key-value pair specified as "case:value" where +// the value must either be 'ignore' or 'strict'. +// The 'ignore' value specifies that matching is case-insensitive +// where dashes and underscores are also ignored. If multiple fields match, +// the first declared field in breadth-first order takes precedence. +// The 'strict' value specifies that matching is case-sensitive. +// This takes precedence over the [MatchCaseInsensitiveNames] option. +// +// - inline: The "inline" option specifies that +// the JSON representable content of this field type is to be promoted +// as if they were specified in the parent struct. +// It is the JSON equivalent of Go struct embedding. +// A Go embedded field is implicitly inlined unless an explicit JSON name +// is specified. The inlined field must be a Go struct +// (that does not implement any JSON methods), [jsontext.Value], +// map[~string]T, or an unnamed pointer to such types. When marshaling, +// inlined fields from a pointer type are omitted if it is nil. +// Inlined fields of type [jsontext.Value] and map[~string]T are called +// “inlined fallbacks” as they can represent all possible +// JSON object members not directly handled by the parent struct. +// Only one inlined fallback field may be specified in a struct, +// while many non-fallback fields may be specified. This option +// must not be specified with any other option (including the JSON name). +// +// - unknown: The "unknown" option is a specialized variant +// of the inlined fallback to indicate that this Go struct field +// contains any number of unknown JSON object members. The field type must +// be a [jsontext.Value], map[~string]T, or an unnamed pointer to such types. +// If [DiscardUnknownMembers] is specified when marshaling, +// the contents of this field are ignored. +// If [RejectUnknownMembers] is specified when unmarshaling, +// any unknown object members are rejected regardless of whether +// an inlined fallback with the "unknown" option exists. This option +// must not be specified with any other option (including the JSON name). +// +// - format: The "format" option specifies a format flag +// used to specialize the formatting of the field value. +// The option is a key-value pair specified as "format:value" where +// the value must be either a literal consisting of letters and numbers +// (e.g., "format:RFC3339") or a single-quoted string literal +// (e.g., "format:'2006-01-02'"). The interpretation of the format flag +// is determined by the struct field type. +// +// The "omitzero" and "omitempty" options are mostly semantically identical. +// The former is defined in terms of the Go type system, +// while the latter in terms of the JSON type system. +// Consequently they behave differently in some circumstances. +// For example, only a nil slice or map is omitted under "omitzero", while +// an empty slice or map is omitted under "omitempty" regardless of nilness. +// The "omitzero" option is useful for types with a well-defined zero value +// (e.g., [net/netip.Addr]) or have an IsZero method (e.g., [time.Time.IsZero]). +// +// Every Go struct corresponds to a list of JSON representable fields +// which is constructed by performing a breadth-first search over +// all struct fields (excluding unexported or ignored fields), +// where the search recursively descends into inlined structs. +// The set of non-inlined fields in a struct must have unique JSON names. +// If multiple fields all have the same JSON name, then the one +// at shallowest depth takes precedence and the other fields at deeper depths +// are excluded from the list of JSON representable fields. +// If multiple fields at the shallowest depth have the same JSON name, +// but exactly one is explicitly tagged with a JSON name, +// then that field takes precedence and all others are excluded from the list. +// This is analogous to Go visibility rules for struct field selection +// with embedded struct types. +// +// Marshaling or unmarshaling a non-empty struct +// without any JSON representable fields results in a [SemanticError]. +// Unexported fields must not have any `json` tags except for `json:"-"`. +// +// # Security Considerations +// +// JSON is frequently used as a data interchange format to communicate +// between different systems, possibly implemented in different languages. +// For interoperability and security reasons, it is important that +// all implementations agree upon the semantic meaning of the data. +// +// [For example, suppose we have two micro-services.] +// The first service is responsible for authenticating a JSON request, +// while the second service is responsible for executing the request +// (having assumed that the prior service authenticated the request). +// If an attacker were able to maliciously craft a JSON request such that +// both services believe that the same request is from different users, +// it could bypass the authenticator with valid credentials for one user, +// but maliciously perform an action on behalf of a different user. +// +// According to RFC 8259, there unfortunately exist many JSON texts +// that are syntactically valid but semantically ambiguous. +// For example, the standard does not define how to interpret duplicate +// names within an object. +// +// The v1 [encoding/json] and [encoding/json/v2] packages +// interpret some inputs in different ways. In particular: +// +// - The standard specifies that JSON must be encoded using UTF-8. +// By default, v1 replaces invalid bytes of UTF-8 in JSON strings +// with the Unicode replacement character, +// while v2 rejects inputs with invalid UTF-8. +// To change the default, specify the [jsontext.AllowInvalidUTF8] option. +// The replacement of invalid UTF-8 is a form of data corruption +// that alters the precise meaning of strings. +// +// - The standard does not specify a particular behavior when +// duplicate names are encountered within a JSON object, +// which means that different implementations may behave differently. +// By default, v1 allows for the presence of duplicate names, +// while v2 rejects duplicate names. +// To change the default, specify the [jsontext.AllowDuplicateNames] option. +// If allowed, object members are processed in the order they are observed, +// meaning that later values will replace or be merged into prior values, +// depending on the Go value type. +// +// - The standard defines a JSON object as an unordered collection of name/value pairs. +// While ordering can be observed through the underlying [jsontext] API, +// both v1 and v2 generally avoid exposing the ordering. +// No application should semantically depend on the order of object members. +// Allowing duplicate names is a vector through which ordering of members +// can accidentally be observed and depended upon. +// +// - The standard suggests that JSON object names are typically compared +// based on equality of the sequence of Unicode code points, +// which implies that comparing names is often case-sensitive. +// When unmarshaling a JSON object into a Go struct, +// by default, v1 uses a (loose) case-insensitive match on the name, +// while v2 uses a (strict) case-sensitive match on the name. +// To change the default, specify the [MatchCaseInsensitiveNames] option. +// The use of case-insensitive matching provides another vector through +// which duplicate names can occur. Allowing case-insensitive matching +// means that v1 or v2 might interpret JSON objects differently from most +// other JSON implementations (which typically use a case-sensitive match). +// +// - The standard does not specify a particular behavior when +// an unknown name in a JSON object is encountered. +// When unmarshaling a JSON object into a Go struct, by default +// both v1 and v2 ignore unknown names and their corresponding values. +// To change the default, specify the [RejectUnknownMembers] option. +// +// - The standard suggests that implementations may use a float64 +// to represent a JSON number. Consequently, large JSON integers +// may lose precision when stored as a floating-point type. +// Both v1 and v2 correctly preserve precision when marshaling and +// unmarshaling a concrete integer type. However, even if v1 and v2 +// preserve precision for concrete types, other JSON implementations +// may not be able to preserve precision for outputs produced by v1 or v2. +// The `string` tag option can be used to specify that an integer type +// is to be quoted within a JSON string to avoid loss of precision. +// Furthermore, v1 and v2 may still lose precision when unmarshaling +// into an any interface value, where unmarshal uses a float64 +// by default to represent a JSON number. +// To change the default, specify the [WithUnmarshalers] option +// with a custom unmarshaler that pre-populates the interface value +// with a concrete Go type that can preserve precision. +// +// RFC 8785 specifies a canonical form for any JSON text, +// which explicitly defines specific behaviors that RFC 8259 leaves undefined. +// In theory, if a text can successfully [jsontext.Value.Canonicalize] +// without changing the semantic meaning of the data, then it provides a +// greater degree of confidence that the data is more secure and interoperable. +// +// The v2 API generally chooses more secure defaults than v1, +// but care should still be taken with large integers or unknown members. +// +// [For example, suppose we have two micro-services.]: https://www.youtube.com/watch?v=avilmOcHKHE&t=1057s +package json + +import ( + "encoding/json/jsontext" + "encoding/json/v2" + "io" +) + +// Marshal serializes a Go value as a []byte according to the provided +// marshal and encode options (while ignoring unmarshal or decode options). +// It does not terminate the output with a newline. +// +// Type-specific marshal functions and methods take precedence +// over the default representation of a value. +// Functions or methods that operate on *T are only called when encoding +// a value of type T (by taking its address) or a non-nil value of *T. +// Marshal ensures that a value is always addressable +// (by boxing it on the heap if necessary) so that +// these functions and methods can be consistently called. For performance, +// it is recommended that Marshal be passed a non-nil pointer to the value. +// +// The input value is encoded as JSON according the following rules: +// +// - If any type-specific functions in a [WithMarshalers] option match +// the value type, then those functions are called to encode the value. +// If all applicable functions return [SkipFunc], +// then the value is encoded according to subsequent rules. +// +// - If the value type implements [MarshalerTo], +// then the MarshalJSONTo method is called to encode the value. +// +// - If the value type implements [Marshaler], +// then the MarshalJSON method is called to encode the value. +// +// - If the value type implements [encoding.TextAppender], +// then the AppendText method is called to encode the value and +// subsequently encode its result as a JSON string. +// +// - If the value type implements [encoding.TextMarshaler], +// then the MarshalText method is called to encode the value and +// subsequently encode its result as a JSON string. +// +// - Otherwise, the value is encoded according to the value's type +// as described in detail below. +// +// Most Go types have a default JSON representation. +// Certain types support specialized formatting according to +// a format flag optionally specified in the Go struct tag +// for the struct field that contains the current value +// (see the “JSON Representation of Go structs” section for more details). +// +// The representation of each type is as follows: +// +// - A Go boolean is encoded as a JSON boolean (e.g., true or false). +// It does not support any custom format flags. +// +// - A Go string is encoded as a JSON string. +// It does not support any custom format flags. +// +// - A Go []byte or [N]byte is encoded as a JSON string containing +// the binary value encoded using RFC 4648. +// If the format is "base64" or unspecified, then this uses RFC 4648, section 4. +// If the format is "base64url", then this uses RFC 4648, section 5. +// If the format is "base32", then this uses RFC 4648, section 6. +// If the format is "base32hex", then this uses RFC 4648, section 7. +// If the format is "base16" or "hex", then this uses RFC 4648, section 8. +// If the format is "array", then the bytes value is encoded as a JSON array +// where each byte is recursively JSON-encoded as each JSON array element. +// +// - A Go integer is encoded as a JSON number without fractions or exponents. +// If [StringifyNumbers] is specified or encoding a JSON object name, +// then the JSON number is encoded within a JSON string. +// It does not support any custom format flags. +// +// - A Go float is encoded as a JSON number. +// If [StringifyNumbers] is specified or encoding a JSON object name, +// then the JSON number is encoded within a JSON string. +// If the format is "nonfinite", then NaN, +Inf, and -Inf are encoded as +// the JSON strings "NaN", "Infinity", and "-Infinity", respectively. +// Otherwise, the presence of non-finite numbers results in a [SemanticError]. +// +// - A Go map is encoded as a JSON object, where each Go map key and value +// is recursively encoded as a name and value pair in the JSON object. +// The Go map key must encode as a JSON string, otherwise this results +// in a [SemanticError]. The Go map is traversed in a non-deterministic order. +// For deterministic encoding, consider using the [Deterministic] option. +// If the format is "emitnull", then a nil map is encoded as a JSON null. +// If the format is "emitempty", then a nil map is encoded as an empty JSON object, +// regardless of whether [FormatNilMapAsNull] is specified. +// Otherwise by default, a nil map is encoded as an empty JSON object. +// +// - A Go struct is encoded as a JSON object. +// See the “JSON Representation of Go structs” section +// in the package-level documentation for more details. +// +// - A Go slice is encoded as a JSON array, where each Go slice element +// is recursively JSON-encoded as the elements of the JSON array. +// If the format is "emitnull", then a nil slice is encoded as a JSON null. +// If the format is "emitempty", then a nil slice is encoded as an empty JSON array, +// regardless of whether [FormatNilSliceAsNull] is specified. +// Otherwise by default, a nil slice is encoded as an empty JSON array. +// +// - A Go array is encoded as a JSON array, where each Go array element +// is recursively JSON-encoded as the elements of the JSON array. +// The JSON array length is always identical to the Go array length. +// It does not support any custom format flags. +// +// - A Go pointer is encoded as a JSON null if nil, otherwise it is +// the recursively JSON-encoded representation of the underlying value. +// Format flags are forwarded to the encoding of the underlying value. +// +// - A Go interface is encoded as a JSON null if nil, otherwise it is +// the recursively JSON-encoded representation of the underlying value. +// It does not support any custom format flags. +// +// - A Go [time.Time] is encoded as a JSON string containing the timestamp +// formatted in RFC 3339 with nanosecond precision. +// If the format matches one of the format constants declared +// in the time package (e.g., RFC1123), then that format is used. +// If the format is "unix", "unixmilli", "unixmicro", or "unixnano", +// then the timestamp is encoded as a possibly fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds) +// since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. +// To avoid a fractional component, round the timestamp to the relevant unit. +// Otherwise, the format is used as-is with [time.Time.Format] if non-empty. +// +// - A Go [time.Duration] currently has no default representation and +// requires an explicit format to be specified. +// If the format is "sec", "milli", "micro", or "nano", +// then the duration is encoded as a possibly fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds). +// To avoid a fractional component, round the duration to the relevant unit. +// If the format is "units", it is encoded as a JSON string formatted using +// [time.Duration.String] (e.g., "1h30m" for 1 hour 30 minutes). +// If the format is "iso8601", it is encoded as a JSON string using the +// ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) +// using only accurate units of hours, minutes, and seconds. +// +// - All other Go types (e.g., complex numbers, channels, and functions) +// have no default representation and result in a [SemanticError]. +// +// JSON cannot represent cyclic data structures and Marshal does not handle them. +// Passing cyclic structures will result in an error. +func Marshal(in any, opts ...Options) (out []byte, err error) { + return json.Marshal(in, opts...) +} + +// MarshalWrite serializes a Go value into an [io.Writer] according to the provided +// marshal and encode options (while ignoring unmarshal or decode options). +// It does not terminate the output with a newline. +// See [Marshal] for details about the conversion of a Go value into JSON. +func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { + return json.MarshalWrite(out, in, opts...) +} + +// MarshalEncode serializes a Go value into an [jsontext.Encoder] according to +// the provided marshal options (while ignoring unmarshal, encode, or decode options). +// Any marshal-relevant options already specified on the [jsontext.Encoder] +// take lower precedence than the set of options provided by the caller. +// Unlike [Marshal] and [MarshalWrite], encode options are ignored because +// they must have already been specified on the provided [jsontext.Encoder]. +// +// See [Marshal] for details about the conversion of a Go value into JSON. +func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { + return json.MarshalEncode(out, in, opts...) +} + +// Unmarshal decodes a []byte input into a Go value according to the provided +// unmarshal and decode options (while ignoring marshal or encode options). +// The input must be a single JSON value with optional whitespace interspersed. +// The output must be a non-nil pointer. +// +// Type-specific unmarshal functions and methods take precedence +// over the default representation of a value. +// Functions or methods that operate on *T are only called when decoding +// a value of type T (by taking its address) or a non-nil value of *T. +// Unmarshal ensures that a value is always addressable +// (by boxing it on the heap if necessary) so that +// these functions and methods can be consistently called. +// +// The input is decoded into the output according the following rules: +// +// - If any type-specific functions in a [WithUnmarshalers] option match +// the value type, then those functions are called to decode the JSON +// value. If all applicable functions return [SkipFunc], +// then the input is decoded according to subsequent rules. +// +// - If the value type implements [UnmarshalerFrom], +// then the UnmarshalJSONFrom method is called to decode the JSON value. +// +// - If the value type implements [Unmarshaler], +// then the UnmarshalJSON method is called to decode the JSON value. +// +// - If the value type implements [encoding.TextUnmarshaler], +// then the input is decoded as a JSON string and +// the UnmarshalText method is called with the decoded string value. +// This fails with a [SemanticError] if the input is not a JSON string. +// +// - Otherwise, the JSON value is decoded according to the value's type +// as described in detail below. +// +// Most Go types have a default JSON representation. +// Certain types support specialized formatting according to +// a format flag optionally specified in the Go struct tag +// for the struct field that contains the current value +// (see the “JSON Representation of Go structs” section for more details). +// A JSON null may be decoded into every supported Go value where +// it is equivalent to storing the zero value of the Go value. +// If the input JSON kind is not handled by the current Go value type, +// then this fails with a [SemanticError]. Unless otherwise specified, +// the decoded value replaces any pre-existing value. +// +// The representation of each type is as follows: +// +// - A Go boolean is decoded from a JSON boolean (e.g., true or false). +// It does not support any custom format flags. +// +// - A Go string is decoded from a JSON string. +// It does not support any custom format flags. +// +// - A Go []byte or [N]byte is decoded from a JSON string +// containing the binary value encoded using RFC 4648. +// If the format is "base64" or unspecified, then this uses RFC 4648, section 4. +// If the format is "base64url", then this uses RFC 4648, section 5. +// If the format is "base32", then this uses RFC 4648, section 6. +// If the format is "base32hex", then this uses RFC 4648, section 7. +// If the format is "base16" or "hex", then this uses RFC 4648, section 8. +// If the format is "array", then the Go slice or array is decoded from a +// JSON array where each JSON element is recursively decoded for each byte. +// When decoding into a non-nil []byte, the slice length is reset to zero +// and the decoded input is appended to it. +// When decoding into a [N]byte, the input must decode to exactly N bytes, +// otherwise it fails with a [SemanticError]. +// +// - A Go integer is decoded from a JSON number. +// It must be decoded from a JSON string containing a JSON number +// if [StringifyNumbers] is specified or decoding a JSON object name. +// It fails with a [SemanticError] if the JSON number +// has a fractional or exponent component. +// It also fails if it overflows the representation of the Go integer type. +// It does not support any custom format flags. +// +// - A Go float is decoded from a JSON number. +// It must be decoded from a JSON string containing a JSON number +// if [StringifyNumbers] is specified or decoding a JSON object name. +// It fails if it overflows the representation of the Go float type. +// If the format is "nonfinite", then the JSON strings +// "NaN", "Infinity", and "-Infinity" are decoded as NaN, +Inf, and -Inf. +// Otherwise, the presence of such strings results in a [SemanticError]. +// +// - A Go map is decoded from a JSON object, +// where each JSON object name and value pair is recursively decoded +// as the Go map key and value. Maps are not cleared. +// If the Go map is nil, then a new map is allocated to decode into. +// If the decoded key matches an existing Go map entry, the entry value +// is reused by decoding the JSON object value into it. +// The formats "emitnull" and "emitempty" have no effect when decoding. +// +// - A Go struct is decoded from a JSON object. +// See the “JSON Representation of Go structs” section +// in the package-level documentation for more details. +// +// - A Go slice is decoded from a JSON array, where each JSON element +// is recursively decoded and appended to the Go slice. +// Before appending into a Go slice, a new slice is allocated if it is nil, +// otherwise the slice length is reset to zero. +// The formats "emitnull" and "emitempty" have no effect when decoding. +// +// - A Go array is decoded from a JSON array, where each JSON array element +// is recursively decoded as each corresponding Go array element. +// Each Go array element is zeroed before decoding into it. +// It fails with a [SemanticError] if the JSON array does not contain +// the exact same number of elements as the Go array. +// It does not support any custom format flags. +// +// - A Go pointer is decoded based on the JSON kind and underlying Go type. +// If the input is a JSON null, then this stores a nil pointer. +// Otherwise, it allocates a new underlying value if the pointer is nil, +// and recursively JSON decodes into the underlying value. +// Format flags are forwarded to the decoding of the underlying type. +// +// - A Go interface is decoded based on the JSON kind and underlying Go type. +// If the input is a JSON null, then this stores a nil interface value. +// Otherwise, a nil interface value of an empty interface type is initialized +// with a zero Go bool, string, float64, map[string]any, or []any if the +// input is a JSON boolean, string, number, object, or array, respectively. +// If the interface value is still nil, then this fails with a [SemanticError] +// since decoding could not determine an appropriate Go type to decode into. +// For example, unmarshaling into a nil io.Reader fails since +// there is no concrete type to populate the interface value with. +// Otherwise an underlying value exists and it recursively decodes +// the JSON input into it. It does not support any custom format flags. +// +// - A Go [time.Time] is decoded from a JSON string containing the time +// formatted in RFC 3339 with nanosecond precision. +// If the format matches one of the format constants declared in +// the time package (e.g., RFC1123), then that format is used for parsing. +// If the format is "unix", "unixmilli", "unixmicro", or "unixnano", +// then the timestamp is decoded from an optionally fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds) +// since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. +// Otherwise, the format is used as-is with [time.Time.Parse] if non-empty. +// +// - A Go [time.Duration] currently has no default representation and +// requires an explicit format to be specified. +// If the format is "sec", "milli", "micro", or "nano", +// then the duration is decoded from an optionally fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds). +// If the format is "units", it is decoded from a JSON string parsed using +// [time.ParseDuration] (e.g., "1h30m" for 1 hour 30 minutes). +// If the format is "iso8601", it is decoded from a JSON string using the +// ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) +// accepting only accurate units of hours, minutes, or seconds. +// +// - All other Go types (e.g., complex numbers, channels, and functions) +// have no default representation and result in a [SemanticError]. +// +// In general, unmarshaling follows merge semantics (similar to RFC 7396) +// where the decoded Go value replaces the destination value +// for any JSON kind other than an object. +// For JSON objects, the input object is merged into the destination value +// where matching object members recursively apply merge semantics. +func Unmarshal(in []byte, out any, opts ...Options) (err error) { + return json.Unmarshal(in, out, opts...) +} + +// UnmarshalRead deserializes a Go value from an [io.Reader] according to the +// provided unmarshal and decode options (while ignoring marshal or encode options). +// The input must be a single JSON value with optional whitespace interspersed. +// It consumes the entirety of [io.Reader] until [io.EOF] is encountered, +// without reporting an error for EOF. The output must be a non-nil pointer. +// See [Unmarshal] for details about the conversion of JSON into a Go value. +func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { + return json.UnmarshalRead(in, out, opts...) +} + +// UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to +// the provided unmarshal options (while ignoring marshal, encode, or decode options). +// Any unmarshal options already specified on the [jsontext.Decoder] +// take lower precedence than the set of options provided by the caller. +// Unlike [Unmarshal] and [UnmarshalRead], decode options are ignored because +// they must have already been specified on the provided [jsontext.Decoder]. +// +// The input may be a stream of one or more JSON values, +// where this only unmarshals the next JSON value in the stream. +// The output must be a non-nil pointer. +// See [Unmarshal] for details about the conversion of JSON into a Go value. +func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { + return json.UnmarshalDecode(in, out, opts...) +} + +// SkipFunc may be returned by [MarshalToFunc] and [UnmarshalFromFunc] functions. +// +// Any function that returns SkipFunc must not cause observable side effects +// on the provided [jsontext.Encoder] or [jsontext.Decoder]. +// For example, it is permissible to call [jsontext.Decoder.PeekKind], +// but not permissible to call [jsontext.Decoder.ReadToken] or +// [jsontext.Encoder.WriteToken] since such methods mutate the state. +var SkipFunc = json.SkipFunc + +// Marshalers is a list of functions that may override the marshal behavior +// of specific types. Populate [WithMarshalers] to use it with +// [Marshal], [MarshalWrite], or [MarshalEncode]. +// A nil *Marshalers is equivalent to an empty list. +// There are no exported fields or methods on Marshalers. +type Marshalers = json.Marshalers + +// JoinMarshalers constructs a flattened list of marshal functions. +// If multiple functions in the list are applicable for a value of a given type, +// then those earlier in the list take precedence over those that come later. +// If a function returns [SkipFunc], then the next applicable function is called, +// otherwise the default marshaling behavior is used. +// +// For example: +// +// m1 := JoinMarshalers(f1, f2) +// m2 := JoinMarshalers(f0, m1, f3) // equivalent to m3 +// m3 := JoinMarshalers(f0, f1, f2, f3) // equivalent to m2 +func JoinMarshalers(ms ...*Marshalers) *Marshalers { + return json.JoinMarshalers(ms...) +} + +// Unmarshalers is a list of functions that may override the unmarshal behavior +// of specific types. Populate [WithUnmarshalers] to use it with +// [Unmarshal], [UnmarshalRead], or [UnmarshalDecode]. +// A nil *Unmarshalers is equivalent to an empty list. +// There are no exported fields or methods on Unmarshalers. +type Unmarshalers = json.Unmarshalers + +// JoinUnmarshalers constructs a flattened list of unmarshal functions. +// If multiple functions in the list are applicable for a value of a given type, +// then those earlier in the list take precedence over those that come later. +// If a function returns [SkipFunc], then the next applicable function is called, +// otherwise the default unmarshaling behavior is used. +// +// For example: +// +// u1 := JoinUnmarshalers(f1, f2) +// u2 := JoinUnmarshalers(f0, u1, f3) // equivalent to u3 +// u3 := JoinUnmarshalers(f0, f1, f2, f3) // equivalent to u2 +func JoinUnmarshalers(us ...*Unmarshalers) *Unmarshalers { + return json.JoinUnmarshalers(us...) +} + +// MarshalFunc constructs a type-specific marshaler that +// specifies how to marshal values of type T. +// T can be any type except a named pointer. +// The function is always provided with a non-nil pointer value +// if T is an interface or pointer type. +// +// The function must marshal exactly one JSON value. +// The value of T must not be retained outside the function call. +// It may not return [SkipFunc]. +func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers { + return json.MarshalFunc[T](fn) +} + +// MarshalToFunc constructs a type-specific marshaler that +// specifies how to marshal values of type T. +// T can be any type except a named pointer. +// The function is always provided with a non-nil pointer value +// if T is an interface or pointer type. +// +// The function must marshal exactly one JSON value by calling write methods +// on the provided encoder. It may return [SkipFunc] such that marshaling can +// move on to the next marshal function. However, no mutable method calls may +// be called on the encoder if [SkipFunc] is returned. +// The pointer to [jsontext.Encoder] and the value of T +// must not be retained outside the function call. +func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers { + return json.MarshalToFunc[T](fn) +} + +// UnmarshalFunc constructs a type-specific unmarshaler that +// specifies how to unmarshal values of type T. +// T must be an unnamed pointer or an interface type. +// The function is always provided with a non-nil pointer value. +// +// The function must unmarshal exactly one JSON value. +// The input []byte must not be mutated. +// The input []byte and value T must not be retained outside the function call. +// It may not return [SkipFunc]. +func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers { + return json.UnmarshalFunc[T](fn) +} + +// UnmarshalFromFunc constructs a type-specific unmarshaler that +// specifies how to unmarshal values of type T. +// T must be an unnamed pointer or an interface type. +// The function is always provided with a non-nil pointer value. +// +// The function must unmarshal exactly one JSON value by calling read methods +// on the provided decoder. It may return [SkipFunc] such that unmarshaling can +// move on to the next unmarshal function. However, no mutable method calls may +// be called on the decoder if [SkipFunc] is returned. +// The pointer to [jsontext.Decoder] and the value of T +// must not be retained outside the function call. +func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers { + return json.UnmarshalFromFunc[T](fn) +} + +// Marshaler is implemented by types that can marshal themselves. +// It is recommended that types implement [MarshalerTo] unless the implementation +// is trying to avoid a hard dependency on the "jsontext" package. +// +// It is recommended that implementations return a buffer that is safe +// for the caller to retain and potentially mutate. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError]. +type Marshaler = json.Marshaler + +// MarshalerTo is implemented by types that can marshal themselves. +// It is recommended that types implement MarshalerTo instead of [Marshaler] +// since this is both more performant and flexible. +// If a type implements both Marshaler and MarshalerTo, +// then MarshalerTo takes precedence. In such a case, both implementations +// should aim to have equivalent behavior for the default marshal options. +// +// The implementation must write only one JSON value to the Encoder and +// must not retain the pointer to [jsontext.Encoder]. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError], +// unless it is an IO error. +type MarshalerTo = json.MarshalerTo + +// Unmarshaler is implemented by types that can unmarshal themselves. +// It is recommended that types implement [UnmarshalerFrom] unless the implementation +// is trying to avoid a hard dependency on the "jsontext" package. +// +// The input can be assumed to be a valid encoding of a JSON value +// if called from unmarshal functionality in this package. +// UnmarshalJSON must copy the JSON data if it is retained after returning. +// It is recommended that UnmarshalJSON implement merge semantics when +// unmarshaling into a pre-populated value. +// +// Implementations must not retain or mutate the input []byte. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError]. +type Unmarshaler = json.Unmarshaler + +// UnmarshalerFrom is implemented by types that can unmarshal themselves. +// It is recommended that types implement UnmarshalerFrom instead of [Unmarshaler] +// since this is both more performant and flexible. +// If a type implements both Unmarshaler and UnmarshalerFrom, +// then UnmarshalerFrom takes precedence. In such a case, both implementations +// should aim to have equivalent behavior for the default unmarshal options. +// +// The implementation must read only one JSON value from the Decoder. +// It is recommended that UnmarshalJSONFrom implement merge semantics when +// unmarshaling into a pre-populated value. +// +// Implementations must not retain the pointer to [jsontext.Decoder]. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError], +// unless it is a [jsontext.SyntacticError] or an IO error. +type UnmarshalerFrom = json.UnmarshalerFrom + +// ErrUnknownName indicates that a JSON object member could not be +// unmarshaled because the name is not known to the target Go struct. +// This error is directly wrapped within a [SemanticError] when produced. +// +// The name of an unknown JSON object member can be extracted as: +// +// err := ... +// var serr json.SemanticError +// if errors.As(err, &serr) && serr.Err == json.ErrUnknownName { +// ptr := serr.JSONPointer // JSON pointer to unknown name +// name := ptr.LastToken() // unknown name itself +// ... +// } +// +// This error is only returned if [RejectUnknownMembers] is true. +var ErrUnknownName = json.ErrUnknownName + +// SemanticError describes an error determining the meaning +// of JSON data as Go data or vice-versa. +// +// If a [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom] method +// returns a SemanticError when called by the [json] package, +// then the ByteOffset, JSONPointer, and GoType fields are automatically +// populated by the calling context if they are the zero value. +// +// The contents of this error as produced by this package may change over time. +type SemanticError = json.SemanticError + +// Options configure [Marshal], [MarshalWrite], [MarshalEncode], +// [Unmarshal], [UnmarshalRead], and [UnmarshalDecode] with specific features. +// Each function takes in a variadic list of options, where properties +// set in later options override the value of previously set properties. +// +// The Options type is identical to [encoding/json.Options] and +// [encoding/json/jsontext.Options]. Options from the other packages can +// be used interchangeably with functionality in this package. +// +// Options represent either a singular option or a set of options. +// It can be functionally thought of as a Go map of option properties +// (even though the underlying implementation avoids Go maps for performance). +// +// The constructors (e.g., [Deterministic]) return a singular option value: +// +// opt := Deterministic(true) +// +// which is analogous to creating a single entry map: +// +// opt := Options{"Deterministic": true} +// +// [JoinOptions] composes multiple options values to together: +// +// out := JoinOptions(opts...) +// +// which is analogous to making a new map and copying the options over: +// +// out := make(Options) +// for _, m := range opts { +// for k, v := range m { +// out[k] = v +// } +// } +// +// [GetOption] looks up the value of options parameter: +// +// v, ok := GetOption(opts, Deterministic) +// +// which is analogous to a Go map lookup: +// +// v, ok := Options["Deterministic"] +// +// There is a single Options type, which is used with both marshal and unmarshal. +// Some options affect both operations, while others only affect one operation: +// +// - [StringifyNumbers] affects marshaling and unmarshaling +// - [Deterministic] affects marshaling only +// - [FormatNilSliceAsNull] affects marshaling only +// - [FormatNilMapAsNull] affects marshaling only +// - [OmitZeroStructFields] affects marshaling only +// - [MatchCaseInsensitiveNames] affects marshaling and unmarshaling +// - [DiscardUnknownMembers] affects marshaling only +// - [RejectUnknownMembers] affects unmarshaling only +// - [WithMarshalers] affects marshaling only +// - [WithUnmarshalers] affects unmarshaling only +// +// Options that do not affect a particular operation are ignored. +type Options = json.Options + +// JoinOptions coalesces the provided list of options into a single Options. +// Properties set in later options override the value of previously set properties. +func JoinOptions(srcs ...Options) Options { + return json.JoinOptions(srcs...) +} + +// GetOption returns the value stored in opts with the provided setter, +// reporting whether the value is present. +// +// Example usage: +// +// v, ok := json.GetOption(opts, json.Deterministic) +// +// Options are most commonly introspected to alter the JSON representation of +// [MarshalerTo.MarshalJSONTo] and [UnmarshalerFrom.UnmarshalJSONFrom] methods, and +// [MarshalToFunc] and [UnmarshalFromFunc] functions. +// In such cases, the presence bit should generally be ignored. +func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { + return json.GetOption[T](opts, setter) +} + +// DefaultOptionsV2 is the full set of all options that define v2 semantics. +// It is equivalent to all options under [Options], [encoding/json.Options], +// and [encoding/json/jsontext.Options] being set to false or the zero value, +// except for the options related to whitespace formatting. +func DefaultOptionsV2() Options { + return json.DefaultOptionsV2() +} + +// StringifyNumbers specifies that numeric Go types should be marshaled +// as a JSON string containing the equivalent JSON number value. +// When unmarshaling, numeric Go types are parsed from a JSON string +// containing the JSON number without any surrounding whitespace. +// +// According to RFC 8259, section 6, a JSON implementation may choose to +// limit the representation of a JSON number to an IEEE 754 binary64 value. +// This may cause decoders to lose precision for int64 and uint64 types. +// Quoting JSON numbers as a JSON string preserves the exact precision. +// +// This affects either marshaling or unmarshaling. +func StringifyNumbers(v bool) Options { + return json.StringifyNumbers(v) +} + +// Deterministic specifies that the same input value will be serialized +// as the exact same output bytes. Different processes of +// the same program will serialize equal values to the same bytes, +// but different versions of the same program are not guaranteed +// to produce the exact same sequence of bytes. +// +// This only affects marshaling and is ignored when unmarshaling. +func Deterministic(v bool) Options { + return json.Deterministic(v) +} + +// FormatNilSliceAsNull specifies that a nil Go slice should marshal as a +// JSON null instead of the default representation as an empty JSON array +// (or an empty JSON string in the case of ~[]byte). +// Slice fields explicitly marked with `format:emitempty` still marshal +// as an empty JSON array. +// +// This only affects marshaling and is ignored when unmarshaling. +func FormatNilSliceAsNull(v bool) Options { + return json.FormatNilSliceAsNull(v) +} + +// FormatNilMapAsNull specifies that a nil Go map should marshal as a +// JSON null instead of the default representation as an empty JSON object. +// Map fields explicitly marked with `format:emitempty` still marshal +// as an empty JSON object. +// +// This only affects marshaling and is ignored when unmarshaling. +func FormatNilMapAsNull(v bool) Options { + return json.FormatNilMapAsNull(v) +} + +// OmitZeroStructFields specifies that a Go struct should marshal in such a way +// that all struct fields that are zero are omitted from the marshaled output +// if the value is zero as determined by the "IsZero() bool" method if present, +// otherwise based on whether the field is the zero Go value. +// This is semantically equivalent to specifying the `omitzero` tag option +// on every field in a Go struct. +// +// This only affects marshaling and is ignored when unmarshaling. +func OmitZeroStructFields(v bool) Options { + return json.OmitZeroStructFields(v) +} + +// MatchCaseInsensitiveNames specifies that JSON object members are matched +// against Go struct fields using a case-insensitive match of the name. +// Go struct fields explicitly marked with `case:strict` or `case:ignore` +// always use case-sensitive (or case-insensitive) name matching, +// regardless of the value of this option. +// +// This affects either marshaling or unmarshaling. +// For marshaling, this option may alter the detection of duplicate names +// (assuming [jsontext.AllowDuplicateNames] is false) from inlined fields +// if it matches one of the declared fields in the Go struct. +func MatchCaseInsensitiveNames(v bool) Options { + return json.MatchCaseInsensitiveNames(v) +} + +// DiscardUnknownMembers specifies that marshaling should ignore any +// JSON object members stored in Go struct fields dedicated to storing +// unknown JSON object members. +// +// This only affects marshaling and is ignored when unmarshaling. +func DiscardUnknownMembers(v bool) Options { + return json.DiscardUnknownMembers(v) +} + +// RejectUnknownMembers specifies that unknown members should be rejected +// when unmarshaling a JSON object, regardless of whether there is a field +// to store unknown members. +// +// This only affects unmarshaling and is ignored when marshaling. +func RejectUnknownMembers(v bool) Options { + return json.RejectUnknownMembers(v) +} + +// WithMarshalers specifies a list of type-specific marshalers to use, +// which can be used to override the default marshal behavior for values +// of particular types. +// +// This only affects marshaling and is ignored when unmarshaling. +func WithMarshalers(v *Marshalers) Options { + return json.WithMarshalers(v) +} + +// WithUnmarshalers specifies a list of type-specific unmarshalers to use, +// which can be used to override the default unmarshal behavior for values +// of particular types. +// +// This only affects unmarshaling and is ignored when marshaling. +func WithUnmarshalers(v *Unmarshalers) Options { + return json.WithUnmarshalers(v) +} diff --git a/vendor/github.com/go-json-experiment/json/arshal.go b/vendor/github.com/go-json-experiment/json/arshal.go index 74eac8d0b9a..be24cb8baf7 100644 --- a/vendor/github.com/go-json-experiment/json/arshal.go +++ b/vendor/github.com/go-json-experiment/json/arshal.go @@ -2,15 +2,19 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( "bytes" + "encoding" "io" "reflect" "slices" "strings" "sync" + "time" "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" @@ -18,39 +22,19 @@ import ( "github.com/go-json-experiment/json/jsontext" ) +// Reference encoding and time packages to assist pkgsite +// in being able to hotlink references to those packages. +var ( + _ encoding.TextMarshaler + _ encoding.TextAppender + _ encoding.TextUnmarshaler + _ time.Time + _ time.Duration +) + // export exposes internal functionality of the "jsontext" package. var export = jsontext.Internal.Export(&internal.AllowInternalUse) -// mayReuseOpt reuses coderOpts if joining opts with the coderOpts -// would produce the equivalent set of options. -func mayReuseOpt(coderOpts *jsonopts.Struct, opts []Options) *jsonopts.Struct { - switch len(opts) { - // In the common case, the caller plumbs down options from the caller's caller, - // which is usually the [jsonopts.Struct] constructed by the top-level arshal call. - case 1: - o, _ := opts[0].(*jsonopts.Struct) - if o == coderOpts { - return coderOpts - } - // If the caller provides no options, then just reuse the coder's options, - // which should only contain encoding/decoding related flags. - case 0: - // TODO: This is buggy if coderOpts ever contains non-coder options. - return coderOpts - } - return nil -} - -var structOptionsPool = &sync.Pool{New: func() any { return new(jsonopts.Struct) }} - -func getStructOptions() *jsonopts.Struct { - return structOptionsPool.Get().(*jsonopts.Struct) -} -func putStructOptions(o *jsonopts.Struct) { - *o = jsonopts.Struct{} - structOptionsPool.Put(o) -} - // Marshal serializes a Go value as a []byte according to the provided // marshal and encode options (while ignoring unmarshal or decode options). // It does not terminate the output with a newline. @@ -77,6 +61,10 @@ func putStructOptions(o *jsonopts.Struct) { // - If the value type implements [Marshaler], // then the MarshalJSON method is called to encode the value. // +// - If the value type implements [encoding.TextAppender], +// then the AppendText method is called to encode the value and +// subsequently encode its result as a JSON string. +// // - If the value type implements [encoding.TextMarshaler], // then the MarshalText method is called to encode the value and // subsequently encode its result as a JSON string. @@ -159,19 +147,23 @@ func putStructOptions(o *jsonopts.Struct) { // If the format matches one of the format constants declared // in the time package (e.g., RFC1123), then that format is used. // If the format is "unix", "unixmilli", "unixmicro", or "unixnano", -// then the timestamp is encoded as a JSON number of the number of seconds -// (or milliseconds, microseconds, or nanoseconds) since the Unix epoch, -// which is January 1st, 1970 at 00:00:00 UTC. +// then the timestamp is encoded as a possibly fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds) +// since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. +// To avoid a fractional component, round the timestamp to the relevant unit. // Otherwise, the format is used as-is with [time.Time.Format] if non-empty. // -// - A Go [time.Duration] is encoded as a JSON string containing the duration -// formatted according to [time.Duration.String]. +// - A Go [time.Duration] currently has no default representation and +// requires an explicit format to be specified. // If the format is "sec", "milli", "micro", or "nano", -// then the duration is encoded as a JSON number of the number of seconds -// (or milliseconds, microseconds, or nanoseconds) in the duration. -// If the format is "base60", it is encoded as a JSON string -// using the "H:MM:SS.SSSSSSSSS" representation. -// If the format is "units", it uses [time.Duration.String]. +// then the duration is encoded as a possibly fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds). +// To avoid a fractional component, round the duration to the relevant unit. +// If the format is "units", it is encoded as a JSON string formatted using +// [time.Duration.String] (e.g., "1h30m" for 1 hour 30 minutes). +// If the format is "iso8601", it is encoded as a JSON string using the +// ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) +// using only accurate units of hours, minutes, and seconds. // // - All other Go types (e.g., complex numbers, channels, and functions) // have no default representation and result in a [SemanticError]. @@ -208,20 +200,21 @@ func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { // MarshalEncode serializes a Go value into an [jsontext.Encoder] according to // the provided marshal options (while ignoring unmarshal, encode, or decode options). +// Any marshal-relevant options already specified on the [jsontext.Encoder] +// take lower precedence than the set of options provided by the caller. // Unlike [Marshal] and [MarshalWrite], encode options are ignored because // they must have already been specified on the provided [jsontext.Encoder]. +// // See [Marshal] for details about the conversion of a Go value into JSON. func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { xe := export.Encoder(out) - mo := mayReuseOpt(&xe.Struct, opts) - if mo == nil { - mo = getStructOptions() - defer putStructOptions(mo) - mo.Join(opts...) - mo.CopyCoderOptions(&xe.Struct) + if len(opts) > 0 { + optsOriginal := xe.Struct + defer func() { xe.Struct = optsOriginal }() + xe.Struct.JoinWithoutCoderOptions(opts...) } - err = marshalEncode(out, in, mo) - if err != nil && mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + err = marshalEncode(out, in, &xe.Struct) + if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { return internal.TransformMarshalError(in, err) } return err @@ -388,19 +381,21 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro // If the format matches one of the format constants declared in // the time package (e.g., RFC1123), then that format is used for parsing. // If the format is "unix", "unixmilli", "unixmicro", or "unixnano", -// then the timestamp is decoded from a JSON number of the number of seconds -// (or milliseconds, microseconds, or nanoseconds) since the Unix epoch, -// which is January 1st, 1970 at 00:00:00 UTC. +// then the timestamp is decoded from an optionally fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds) +// since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. // Otherwise, the format is used as-is with [time.Time.Parse] if non-empty. // -// - A Go [time.Duration] is decoded from a JSON string by -// passing the decoded string to [time.ParseDuration]. +// - A Go [time.Duration] currently has no default representation and +// requires an explicit format to be specified. // If the format is "sec", "milli", "micro", or "nano", -// then the duration is decoded from a JSON number of the number of seconds -// (or milliseconds, microseconds, or nanoseconds) in the duration. -// If the format is "base60", it is decoded from a JSON string -// using the "H:MM:SS.SSSSSSSSS" representation. -// If the format is "units", it uses [time.ParseDuration]. +// then the duration is decoded from an optionally fractional JSON number +// of the number of seconds (or milliseconds, microseconds, or nanoseconds). +// If the format is "units", it is decoded from a JSON string parsed using +// [time.ParseDuration] (e.g., "1h30m" for 1 hour 30 minutes). +// If the format is "iso8601", it is decoded from a JSON string using the +// ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) +// accepting only accurate units of hours, minutes, or seconds. // // - All other Go types (e.g., complex numbers, channels, and functions) // have no default representation and result in a [SemanticError]. @@ -414,7 +409,7 @@ func Unmarshal(in []byte, out any, opts ...Options) (err error) { dec := export.GetBufferedDecoder(in, opts...) defer export.PutBufferedDecoder(dec) xd := export.Decoder(dec) - err = unmarshalFull(dec, out, &xd.Struct) + err = unmarshalDecode(dec, out, &xd.Struct, true) if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { return internal.TransformUnmarshalError(out, err) } @@ -431,49 +426,39 @@ func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { dec := export.GetStreamingDecoder(in, opts...) defer export.PutStreamingDecoder(dec) xd := export.Decoder(dec) - err = unmarshalFull(dec, out, &xd.Struct) + err = unmarshalDecode(dec, out, &xd.Struct, true) if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { return internal.TransformUnmarshalError(out, err) } return err } -func unmarshalFull(in *jsontext.Decoder, out any, uo *jsonopts.Struct) error { - switch err := unmarshalDecode(in, out, uo); err { - case nil: - return export.Decoder(in).CheckEOF() - case io.EOF: - return io.ErrUnexpectedEOF - default: - return err - } -} - // UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to // the provided unmarshal options (while ignoring marshal, encode, or decode options). +// Any unmarshal options already specified on the [jsontext.Decoder] +// take lower precedence than the set of options provided by the caller. // Unlike [Unmarshal] and [UnmarshalRead], decode options are ignored because // they must have already been specified on the provided [jsontext.Decoder]. +// // The input may be a stream of one or more JSON values, // where this only unmarshals the next JSON value in the stream. // The output must be a non-nil pointer. // See [Unmarshal] for details about the conversion of JSON into a Go value. func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { xd := export.Decoder(in) - uo := mayReuseOpt(&xd.Struct, opts) - if uo == nil { - uo = getStructOptions() - defer putStructOptions(uo) - uo.Join(opts...) - uo.CopyCoderOptions(&xd.Struct) + if len(opts) > 0 { + optsOriginal := xd.Struct + defer func() { xd.Struct = optsOriginal }() + xd.Struct.JoinWithoutCoderOptions(opts...) } - err = unmarshalDecode(in, out, uo) - if err != nil && uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + err = unmarshalDecode(in, out, &xd.Struct, false) + if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { return internal.TransformUnmarshalError(out, err) } return err } -func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err error) { +func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct, last bool) (err error) { v := reflect.ValueOf(out) if v.Kind() != reflect.Pointer || v.IsNil() { return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference} @@ -484,7 +469,11 @@ func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err er // In legacy semantics, the entirety of the next JSON value // was validated before attempting to unmarshal it. if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { - if err := export.Decoder(in).CheckNextValue(); err != nil { + if err := export.Decoder(in).CheckNextValue(last); err != nil { + if err == io.EOF && last { + offset := in.InputOffset() + int64(len(in.UnreadBuffer())) + return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} + } return err } } @@ -498,8 +487,15 @@ func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err er if !uo.Flags.Get(jsonflags.AllowDuplicateNames) { export.Decoder(in).Tokens.InvalidateDisabledNamespaces() } + if err == io.EOF && last { + offset := in.InputOffset() + int64(len(in.UnreadBuffer())) + return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} + } return err } + if last { + return export.Decoder(in).CheckEOF() + } return nil } @@ -523,6 +519,9 @@ func newAddressableValue(t reflect.Type) addressableValue { return addressableValue{reflect.New(t).Elem(), true} } +// TODO: Remove *jsonopts.Struct argument from [marshaler] and [unmarshaler]. +// This can be directly accessed on the encoder or decoder. + // All marshal and unmarshal behavior is implemented using these signatures. // The *jsonopts.Struct argument is guaranteed to identical to or at least // a strict super-set of the options in Encoder.Struct or Decoder.Struct. diff --git a/vendor/github.com/go-json-experiment/json/arshal_any.go b/vendor/github.com/go-json-experiment/json/arshal_any.go index 5ff4bf91c02..a9db1812ab9 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_any.go +++ b/vendor/github.com/go-json-experiment/json/arshal_any.go @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( "cmp" + "math" "reflect" "strconv" @@ -33,20 +36,23 @@ func marshalValueAny(enc *jsontext.Encoder, val any, mo *jsonopts.Struct) error case string: return enc.WriteToken(jsontext.String(val)) case float64: + if math.IsNaN(val) || math.IsInf(val, 0) { + break // use default logic below + } return enc.WriteToken(jsontext.Float(val)) case map[string]any: return marshalObjectAny(enc, val, mo) case []any: return marshalArrayAny(enc, val, mo) - default: - v := newAddressableValue(reflect.TypeOf(val)) - v.Set(reflect.ValueOf(val)) - marshal := lookupArshaler(v.Type()).marshal - if mo.Marshalers != nil { - marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, v.Type()) - } - return marshal(enc, v, mo) } + + v := newAddressableValue(reflect.TypeOf(val)) + v.Set(reflect.ValueOf(val)) + marshal := lookupArshaler(v.Type()).marshal + if mo.Marshalers != nil { + marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, v.Type()) + } + return marshal(enc, v, mo) } // unmarshalValueAny unmarshals a JSON value as a Go any. @@ -102,7 +108,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St if xe.Tokens.Depth() > startDetectingCyclesAfter { v := reflect.ValueOf(obj) if err := visitPointer(&xe.SeenPointers, v); err != nil { - return newMarshalErrorBefore(enc, anyType, err) + return newMarshalErrorBefore(enc, mapStringAnyType, err) } defer leavePointer(&xe.SeenPointers, v) } @@ -123,7 +129,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St } } - if err := enc.WriteToken(jsontext.ObjectStart); err != nil { + if err := enc.WriteToken(jsontext.BeginObject); err != nil { return err } // A Go map guarantees that each entry has a unique key @@ -158,7 +164,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St } putStrings(names) } - if err := enc.WriteToken(jsontext.ObjectEnd); err != nil { + if err := enc.WriteToken(jsontext.EndObject); err != nil { return err } return nil @@ -239,7 +245,7 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro } } - if err := enc.WriteToken(jsontext.ArrayStart); err != nil { + if err := enc.WriteToken(jsontext.BeginArray); err != nil { return err } for _, val := range arr { @@ -247,7 +253,7 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro return err } } - if err := enc.WriteToken(jsontext.ArrayEnd); err != nil { + if err := enc.WriteToken(jsontext.EndArray); err != nil { return err } return nil diff --git a/vendor/github.com/go-json-experiment/json/arshal_default.go b/vendor/github.com/go-json-experiment/json/arshal_default.go index 21c183611a9..8084fcccc7a 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_default.go +++ b/vendor/github.com/go-json-experiment/json/arshal_default.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -126,7 +128,7 @@ func makeBoolArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } // Optimize for marshaling without preceding whitespace. @@ -151,7 +153,7 @@ func makeBoolArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } tok, err := dec.ReadToken() if err != nil { @@ -188,7 +190,7 @@ func makeBoolArshaler(t reflect.Type) *arshaler { return nil } } - return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) + return newUnmarshalErrorAfterWithSkipping(dec, t, nil) } return &fncs } @@ -198,7 +200,7 @@ func makeStringArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } // Optimize for marshaling without preceding whitespace. @@ -235,7 +237,7 @@ func makeStringArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } var flags jsonwire.ValueFlags val, err := xd.ReadValue(&flags) @@ -325,10 +327,11 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler { mo.Format = "" return marshalArray(enc, va, mo) default: - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } - } else if mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && - (va.Kind() == reflect.Array || hasMarshaler) { + } else if mo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array { + return marshalArray(enc, va, mo) + } else if mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && hasMarshaler { return marshalArray(enc, va, mo) } if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && va.Kind() == reflect.Slice && va.IsNil() { @@ -362,10 +365,11 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler { uo.Format = "" return unmarshalArray(dec, va, uo) default: - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } - } else if uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && - (va.Kind() == reflect.Array || dec.PeekKind() == '[') { + } else if uo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array { + return unmarshalArray(dec, va, uo) + } else if uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && dec.PeekKind() == '[' { return unmarshalArray(dec, va, uo) } var flags jsonwire.ValueFlags @@ -393,7 +397,7 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler { if err != nil { return newUnmarshalErrorAfter(dec, t, err) } - if len(val) != encodedLen(len(b)) && !uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) { + if len(val) != encodedLen(len(b)) && !uo.Flags.Get(jsonflags.ParseBytesWithLooseRFC4648) { // TODO(https://go.dev/issue/53845): RFC 4648, section 3.3, // specifies that non-alphabet characters must be rejected. // Unfortunately, the "base32" and "base64" packages allow @@ -429,7 +433,7 @@ func makeIntArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } // Optimize for marshaling without preceding whitespace or string escaping. @@ -450,7 +454,7 @@ func makeIntArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags @@ -516,7 +520,7 @@ func makeUintArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } // Optimize for marshaling without preceding whitespace or string escaping. @@ -537,7 +541,7 @@ func makeUintArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags @@ -598,7 +602,7 @@ func makeFloatArshaler(t reflect.Type) *arshaler { if mo.Format == "nonfinite" { allowNonFinite = true } else { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } } @@ -633,7 +637,7 @@ func makeFloatArshaler(t reflect.Type) *arshaler { if uo.Format == "nonfinite" { allowNonFinite = true } else { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } } stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) @@ -733,7 +737,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { emitNull = false mo.Format = "" default: - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } } @@ -755,7 +759,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { } once.Do(init) - if err := enc.WriteToken(jsontext.ObjectStart); err != nil { + if err := enc.WriteToken(jsontext.BeginObject); err != nil { return err } if n > 0 { @@ -866,7 +870,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { } } } - if err := enc.WriteToken(jsontext.ObjectEnd); err != nil { + if err := enc.WriteToken(jsontext.EndObject); err != nil { return err } return nil @@ -878,7 +882,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { case "emitnull", "emitempty": uo.Format = "" // only relevant for marshaling default: - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } } tok, err := dec.ReadToken() @@ -988,7 +992,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { } return errUnmarshal } - return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) + return newUnmarshalErrorAfterWithSkipping(dec, t, nil) } return &fncs } @@ -1033,13 +1037,13 @@ func makeStructArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } once.Do(init) if errInit != nil && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { return newMarshalErrorBefore(enc, errInit.GoType, errInit.Err) } - if err := enc.WriteToken(jsontext.ObjectStart); err != nil { + if err := enc.WriteToken(jsontext.BeginObject); err != nil { return err } var seenIdxs uintSet @@ -1063,7 +1067,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { } // Check for the legacy definition of omitempty. - if f.omitempty && mo.Flags.Get(jsonflags.OmitEmptyWithLegacyDefinition) && isLegacyEmpty(v) { + if f.omitempty && mo.Flags.Get(jsonflags.OmitEmptyWithLegacySemantics) && isLegacyEmpty(v) { continue } @@ -1078,7 +1082,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { // OmitEmpty skips the field if the marshaled JSON value is empty, // which we can know up front if there are no custom marshalers, // otherwise we must marshal the value and unwrite it if empty. - if f.omitempty && !mo.Flags.Get(jsonflags.OmitEmptyWithLegacyDefinition) && + if f.omitempty && !mo.Flags.Get(jsonflags.OmitEmptyWithLegacySemantics) && !nonDefault && f.isEmpty != nil && f.isEmpty(v) { continue // fast path for omitempty } @@ -1143,7 +1147,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { } // Try unwriting the member if empty (slow path for omitempty). - if f.omitempty && !mo.Flags.Get(jsonflags.OmitEmptyWithLegacyDefinition) { + if f.omitempty && !mo.Flags.Get(jsonflags.OmitEmptyWithLegacySemantics) { var prevName *string if prevIdx >= 0 { prevName = &fields.flattened[prevIdx].name @@ -1187,7 +1191,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { return err } } - if err := enc.WriteToken(jsontext.ObjectEnd); err != nil { + if err := enc.WriteToken(jsontext.EndObject); err != nil { return err } return nil @@ -1195,7 +1199,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } tok, err := dec.ReadToken() if err != nil { @@ -1313,7 +1317,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { } return errUnmarshal } - return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) + return newUnmarshalErrorAfterWithSkipping(dec, t, nil) } return &fncs } @@ -1410,7 +1414,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { emitNull = false mo.Format = "" default: - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } } @@ -1432,7 +1436,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { } once.Do(init) - if err := enc.WriteToken(jsontext.ArrayStart); err != nil { + if err := enc.WriteToken(jsontext.BeginArray); err != nil { return err } marshal := valFncs.marshal @@ -1445,7 +1449,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { return err } } - if err := enc.WriteToken(jsontext.ArrayEnd); err != nil { + if err := enc.WriteToken(jsontext.EndArray); err != nil { return err } return nil @@ -1458,7 +1462,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { case "emitnull", "emitempty": uo.Format = "" // only relevant for marshaling default: - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } } @@ -1514,7 +1518,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { } return errUnmarshal } - return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) + return newUnmarshalErrorAfterWithSkipping(dec, t, nil) } return &fncs } @@ -1535,10 +1539,10 @@ func makeArrayArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } once.Do(init) - if err := enc.WriteToken(jsontext.ArrayStart); err != nil { + if err := enc.WriteToken(jsontext.BeginArray); err != nil { return err } marshal := valFncs.marshal @@ -1551,7 +1555,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler { return err } } - if err := enc.WriteToken(jsontext.ArrayEnd); err != nil { + if err := enc.WriteToken(jsontext.EndArray); err != nil { return err } return nil @@ -1559,7 +1563,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } tok, err := dec.ReadToken() if err != nil { @@ -1612,7 +1616,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler { } return errUnmarshal } - return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) + return newUnmarshalErrorAfterWithSkipping(dec, t, nil) } return &fncs } @@ -1686,8 +1690,6 @@ func makePointerArshaler(t reflect.Type) *arshaler { return &fncs } -var errNilInterface = errors.New("cannot derive concrete type for nil interface with finite type set") - func makeInterfaceArshaler(t reflect.Type) *arshaler { // NOTE: Values retrieved from an interface are not addressable, // so we shallow copy the values to make them addressable and @@ -1704,7 +1706,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } if va.IsNil() { return enc.WriteToken(jsontext.Null) @@ -1720,7 +1722,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { case jsonMarshalerType: v2.Set(reflect.ValueOf(struct{ Marshaler }{va.Elem().Interface().(Marshaler)})) case textAppenderType: - v2.Set(reflect.ValueOf(struct{ encodingTextAppender }{va.Elem().Interface().(encodingTextAppender)})) + v2.Set(reflect.ValueOf(struct{ encoding.TextAppender }{va.Elem().Interface().(encoding.TextAppender)})) case textMarshalerType: v2.Set(reflect.ValueOf(struct{ encoding.TextMarshaler }{va.Elem().Interface().(encoding.TextMarshaler)})) } @@ -1744,7 +1746,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } if uo.Flags.Get(jsonflags.MergeWithLegacySemantics) && !va.IsNil() { // Legacy merge behavior is difficult to explain. @@ -1793,7 +1795,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { k := dec.PeekKind() if !isAnyType(t) { - return newUnmarshalErrorBeforeWithSkipping(dec, uo, t, errNilInterface) + return newUnmarshalErrorBeforeWithSkipping(dec, t, internal.ErrNilInterface) } switch k { case 'f', 't': diff --git a/vendor/github.com/go-json-experiment/json/arshal_funcs.go b/vendor/github.com/go-json-experiment/json/arshal_funcs.go index b6b0d083902..2990e9a4ce1 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_funcs.go +++ b/vendor/github.com/go-json-experiment/json/arshal_funcs.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -175,7 +177,8 @@ func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers { typFnc := typedMarshaler{ typ: t, fnc: func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { - val, err := fn(va.castTo(t).Interface().(T)) + v, _ := reflect.TypeAssert[T](va.castTo(t)) + val, err := fn(v) if err != nil { err = wrapSkipFunc(err, "marshal function of type func(T) ([]byte, error)") if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { @@ -209,9 +212,9 @@ func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers { // on the provided encoder. It may return [SkipFunc] such that marshaling can // move on to the next marshal function. However, no mutable method calls may // be called on the encoder if [SkipFunc] is returned. -// The pointer to [jsontext.Encoder], the value of T, and the [Options] value +// The pointer to [jsontext.Encoder] and the value of T // must not be retained outside the function call. -func MarshalToFunc[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshalers { +func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers { t := reflect.TypeFor[T]() assertCastableTo(t, true) typFnc := typedMarshaler{ @@ -220,7 +223,8 @@ func MarshalToFunc[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshal xe := export.Encoder(enc) prevDepth, prevLength := xe.Tokens.DepthLength() xe.Flags.Set(jsonflags.WithinArshalCall | 1) - err := fn(enc, va.castTo(t).Interface().(T), mo) + v, _ := reflect.TypeAssert[T](va.castTo(t)) + err := fn(enc, v) xe.Flags.Set(jsonflags.WithinArshalCall | 0) currDepth, currLength := xe.Tokens.DepthLength() if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { @@ -267,7 +271,8 @@ func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers { if err != nil { return err // must be a syntactic or I/O error } - err = fn(val, va.castTo(t).Interface().(T)) + v, _ := reflect.TypeAssert[T](va.castTo(t)) + err = fn(val, v) if err != nil { err = wrapSkipFunc(err, "unmarshal function of type func([]byte, T) error") if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { @@ -291,9 +296,9 @@ func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers { // on the provided decoder. It may return [SkipFunc] such that unmarshaling can // move on to the next unmarshal function. However, no mutable method calls may // be called on the decoder if [SkipFunc] is returned. -// The pointer to [jsontext.Decoder], the value of T, and [Options] value +// The pointer to [jsontext.Decoder] and the value of T // must not be retained outside the function call. -func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T, Options) error) *Unmarshalers { +func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers { t := reflect.TypeFor[T]() assertCastableTo(t, false) typFnc := typedUnmarshaler{ @@ -302,7 +307,8 @@ func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T, Options) error) *Unm xd := export.Decoder(dec) prevDepth, prevLength := xd.Tokens.DepthLength() xd.Flags.Set(jsonflags.WithinArshalCall | 1) - err := fn(dec, va.castTo(t).Interface().(T), uo) + v, _ := reflect.TypeAssert[T](va.castTo(t)) + err := fn(dec, v) xd.Flags.Set(jsonflags.WithinArshalCall | 0) currDepth, currLength := xd.Tokens.DepthLength() if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { diff --git a/vendor/github.com/go-json-experiment/json/arshal_inlined.go b/vendor/github.com/go-json-experiment/json/arshal_inlined.go index 362087f3d33..b071851842b 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_inlined.go +++ b/vendor/github.com/go-json-experiment/json/arshal_inlined.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -48,8 +50,7 @@ func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *j } if v.Type() == jsontextValueType { - // TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. - b := *v.Addr().Interface().(*jsontext.Value) + b, _ := reflect.TypeAssert[jsontext.Value](v.Value) if len(b) == 0 { // TODO: Should this be nil? What if it were all whitespace? return nil } @@ -111,7 +112,7 @@ func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *j mk := newAddressableValue(m.Type().Key()) mv := newAddressableValue(m.Type().Elem()) marshalKey := func(mk addressableValue) error { - b, err := jsonwire.AppendQuote(enc.UnusedBuffer(), mk.String(), &mo.Flags) + b, err := jsonwire.AppendQuote(enc.AvailableBuffer(), mk.String(), &mo.Flags) if err != nil { return newMarshalErrorBefore(enc, m.Type().Key(), err) } @@ -172,7 +173,7 @@ func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo v = v.indirect(true) if v.Type() == jsontextValueType { - b := v.Addr().Interface().(*jsontext.Value) + b, _ := reflect.TypeAssert[*jsontext.Value](v.Addr()) if len(*b) == 0 { // TODO: Should this be nil? What if it were all whitespace? *b = append(*b, '{') } else { @@ -186,7 +187,7 @@ func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo *b = append(*b, ',') } } else { - return newUnmarshalErrorAfterWithSkipping(dec, uo, v.Type(), errRawInlinedNotObject) + return newUnmarshalErrorAfterWithSkipping(dec, v.Type(), errRawInlinedNotObject) } } *b = append(*b, quotedName...) diff --git a/vendor/github.com/go-json-experiment/json/arshal_methods.go b/vendor/github.com/go-json-experiment/json/arshal_methods.go index a263c48acad..5a2a11bba2a 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_methods.go +++ b/vendor/github.com/go-json-experiment/json/arshal_methods.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -24,32 +26,25 @@ var ( jsonMarshalerToType = reflect.TypeFor[MarshalerTo]() jsonUnmarshalerType = reflect.TypeFor[Unmarshaler]() jsonUnmarshalerFromType = reflect.TypeFor[UnmarshalerFrom]() - textAppenderType = reflect.TypeFor[encodingTextAppender]() + textAppenderType = reflect.TypeFor[encoding.TextAppender]() textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]() textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]() - // TODO(https://go.dev/issue/62384): Use encoding.TextAppender instead of this hack. - // This exists for now to provide performance benefits to netip types. - // There is no semantic difference with this change. - appenderToType = reflect.TypeFor[interface{ AppendTo([]byte) []byte }]() - allMarshalerTypes = []reflect.Type{jsonMarshalerToType, jsonMarshalerType, textAppenderType, textMarshalerType} allUnmarshalerTypes = []reflect.Type{jsonUnmarshalerFromType, jsonUnmarshalerType, textUnmarshalerType} allMethodTypes = append(allMarshalerTypes, allUnmarshalerTypes...) ) -// TODO(https://go.dev/issue/62384): Use encoding.TextAppender instead -// and document public support for this method in json.Marshal. -type encodingTextAppender interface { - AppendText(b []byte) ([]byte, error) -} - // Marshaler is implemented by types that can marshal themselves. // It is recommended that types implement [MarshalerTo] unless the implementation // is trying to avoid a hard dependency on the "jsontext" package. // // It is recommended that implementations return a buffer that is safe // for the caller to retain and potentially mutate. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError]. type Marshaler interface { MarshalJSON() ([]byte, error) } @@ -62,9 +57,14 @@ type Marshaler interface { // should aim to have equivalent behavior for the default marshal options. // // The implementation must write only one JSON value to the Encoder and -// must not retain the pointer to [jsontext.Encoder] or the [Options] value. +// must not retain the pointer to [jsontext.Encoder]. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError], +// unless it is an IO error. type MarshalerTo interface { - MarshalJSONTo(*jsontext.Encoder, Options) error + MarshalJSONTo(*jsontext.Encoder) error // TODO: Should users call the MarshalEncode function or // should/can they call this method directly? Does it matter? @@ -81,6 +81,10 @@ type MarshalerTo interface { // unmarshaling into a pre-populated value. // // Implementations must not retain or mutate the input []byte. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError]. type Unmarshaler interface { UnmarshalJSON([]byte) error } @@ -96,10 +100,14 @@ type Unmarshaler interface { // It is recommended that UnmarshalJSONFrom implement merge semantics when // unmarshaling into a pre-populated value. // -// Implementations must not retain the pointer to [jsontext.Decoder] or -// the [Options] value. +// Implementations must not retain the pointer to [jsontext.Decoder]. +// +// If the returned error is a [SemanticError], then unpopulated fields +// of the error may be populated by [json] with additional context. +// Errors of other types are wrapped within a [SemanticError], +// unless it is a [jsontext.SyntacticError] or an IO error. type UnmarshalerFrom interface { - UnmarshalJSONFrom(*jsontext.Decoder, Options) error + UnmarshalJSONFrom(*jsontext.Decoder) error // TODO: Should users call the UnmarshalDecode function or // should/can they call this method directly? Does it matter? @@ -121,7 +129,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { (needAddr && va.forcedAddr) { return prevMarshal(enc, va, mo) } - marshaler := va.Addr().Interface().(encoding.TextMarshaler) + marshaler, _ := reflect.TypeAssert[encoding.TextMarshaler](va.Addr()) if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) { b2, err := marshaler.MarshalText() return append(b, b2...), err @@ -137,21 +145,6 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { } return nil } - // TODO(https://go.dev/issue/62384): Rely on encoding.TextAppender instead. - if implementsAny(t, appenderToType) && t.PkgPath() == "net/netip" { - fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { - appender := va.Addr().Interface().(interface{ AppendTo([]byte) []byte }) - if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) { - return appender.AppendTo(b), nil - }); err != nil { - if !isSemanticError(err) && !export.IsIOError(err) { - err = newMarshalErrorBefore(enc, t, err) - } - return err - } - return nil - } - } } if needAddr, ok := implements(t, textAppenderType); ok { @@ -162,7 +155,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { (needAddr && va.forcedAddr) { return prevMarshal(enc, va, mo) } - appender := va.Addr().Interface().(encodingTextAppender) + appender, _ := reflect.TypeAssert[encoding.TextAppender](va.Addr()) if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil { err = wrapSkipFunc(err, "append method") if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { @@ -185,7 +178,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { ((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { return prevMarshal(enc, va, mo) } - marshaler := va.Addr().Interface().(Marshaler) + marshaler, _ := reflect.TypeAssert[Marshaler](va.Addr()) val, err := marshaler.MarshalJSON() if err != nil { err = wrapSkipFunc(err, "marshal method") @@ -219,7 +212,8 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { xe := export.Encoder(enc) prevDepth, prevLength := xe.Tokens.DepthLength() xe.Flags.Set(jsonflags.WithinArshalCall | 1) - err := va.Addr().Interface().(MarshalerTo).MarshalJSONTo(enc, mo) + marshaler, _ := reflect.TypeAssert[MarshalerTo](va.Addr()) + err := marshaler.MarshalJSONTo(enc) xe.Flags.Set(jsonflags.WithinArshalCall | 0) currDepth, currLength := xe.Tokens.DepthLength() if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { @@ -258,7 +252,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { return newUnmarshalErrorAfter(dec, t, errNonStringValue) } s := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) - unmarshaler := va.Addr().Interface().(encoding.TextUnmarshaler) + unmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](va.Addr()) if err := unmarshaler.UnmarshalText(s); err != nil { err = wrapSkipFunc(err, "unmarshal method") if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { @@ -285,7 +279,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { if err != nil { return err // must be a syntactic or I/O error } - unmarshaler := va.Addr().Interface().(Unmarshaler) + unmarshaler, _ := reflect.TypeAssert[Unmarshaler](va.Addr()) if err := unmarshaler.UnmarshalJSON(val); err != nil { err = wrapSkipFunc(err, "unmarshal method") if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { @@ -309,7 +303,8 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { xd := export.Decoder(dec) prevDepth, prevLength := xd.Tokens.DepthLength() xd.Flags.Set(jsonflags.WithinArshalCall | 1) - err := va.Addr().Interface().(UnmarshalerFrom).UnmarshalJSONFrom(dec, uo) + unmarshaler, _ := reflect.TypeAssert[UnmarshalerFrom](va.Addr()) + err := unmarshaler.UnmarshalJSONFrom(dec) xd.Flags.Set(jsonflags.WithinArshalCall | 0) currDepth, currLength := xd.Tokens.DepthLength() if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { diff --git a/vendor/github.com/go-json-experiment/json/arshal_time.go b/vendor/github.com/go-json-experiment/json/arshal_time.go index 9cb8e80e503..64bdbda2a6a 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_time.go +++ b/vendor/github.com/go-json-experiment/json/arshal_time.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -46,14 +48,16 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var m durationArshaler if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { if !m.initFormat(mo.Format) { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } - } else if mo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { + } else if mo.Flags.Get(jsonflags.FormatDurationAsNano) { return marshalNano(enc, va, mo) + } else { + // TODO(https://go.dev/issue/71631): Decide on default duration representation. + return newMarshalErrorBefore(enc, t, errors.New("no default representation (see https://go.dev/issue/71631); specify an explicit format")) } - // TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. - m.td = *va.Addr().Interface().(*time.Duration) + m.td, _ = reflect.TypeAssert[time.Duration](va.Value) k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) if err := xe.AppendRaw(k, true, m.appendMarshal); err != nil { if !isSyntacticError(err) && !export.IsIOError(err) { @@ -69,15 +73,18 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var u durationArshaler if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { if !u.initFormat(uo.Format) { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } - } else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { + } else if uo.Flags.Get(jsonflags.FormatDurationAsNano) { return unmarshalNano(dec, va, uo) + } else { + // TODO(https://go.dev/issue/71631): Decide on default duration representation. + return newUnmarshalErrorBeforeWithSkipping(dec, t, errors.New("no default representation (see https://go.dev/issue/71631); specify an explicit format")) } stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags - td := va.Addr().Interface().(*time.Duration) + td, _ := reflect.TypeAssert[*time.Duration](va.Addr()) val, err := xd.ReadValue(&flags) if err != nil { return err @@ -117,12 +124,11 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var m timeArshaler if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { if !m.initFormat(mo.Format) { - return newInvalidFormatError(enc, t, mo) + return newInvalidFormatError(enc, t) } } - // TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. - m.tt = *va.Addr().Interface().(*time.Time) + m.tt, _ = reflect.TypeAssert[time.Time](va.Value) k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) if err := xe.AppendRaw(k, !m.hasCustomFormat(), m.appendMarshal); err != nil { if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { @@ -140,15 +146,15 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var u timeArshaler if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { if !u.initFormat(uo.Format) { - return newInvalidFormatError(dec, t, uo) + return newInvalidFormatError(dec, t) } - } else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { + } else if uo.Flags.Get(jsonflags.ParseTimeWithLooseRFC3339) { u.looseRFC3339 = true } stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags - tt := va.Addr().Interface().(*time.Time) + tt, _ := reflect.TypeAssert[*time.Time](va.Addr()) val, err := xd.ReadValue(&flags) if err != nil { return err @@ -198,7 +204,7 @@ type durationArshaler struct { // - 0 uses time.Duration.String // - 1e0, 1e3, 1e6, or 1e9 use a decimal encoding of the duration as // nanoseconds, microseconds, milliseconds, or seconds. - // - 60 uses a "H:MM:SS.SSSSSSSSS" encoding + // - 8601 uses ISO 8601 base uint64 } @@ -214,8 +220,8 @@ func (a *durationArshaler) initFormat(format string) (ok bool) { a.base = 1e3 case "nano": a.base = 1e0 - case "base60": // see https://en.wikipedia.org/wiki/Sexagesimal#Modern_usage - a.base = 60 + case "iso8601": + a.base = 8601 default: return false } @@ -223,15 +229,15 @@ func (a *durationArshaler) initFormat(format string) (ok bool) { } func (a *durationArshaler) isNumeric() bool { - return a.base != 0 && a.base != 60 + return a.base != 0 && a.base != 8601 } func (a *durationArshaler) appendMarshal(b []byte) ([]byte, error) { switch a.base { case 0: return append(b, a.td.String()...), nil - case 60: - return appendDurationBase60(b, a.td), nil + case 8601: + return appendDurationISO8601(b, a.td), nil default: return appendDurationBase10(b, a.td, a.base), nil } @@ -241,8 +247,8 @@ func (a *durationArshaler) unmarshal(b []byte) (err error) { switch a.base { case 0: a.td, err = time.ParseDuration(string(b)) - case 60: - a.td, err = parseDurationBase60(b) + case 8601: + a.td, err = parseDurationISO8601(b) default: a.td, err = parseDurationBase10(b, a.base) } @@ -417,7 +423,7 @@ func appendDurationBase10(b []byte, d time.Duration, pow10 uint64) []byte { // parseDurationBase10 parses d from a decimal fractional number, // where pow10 is a power-of-10 used to scale up the number. func parseDurationBase10(b []byte, pow10 uint64) (time.Duration, error) { - suffix, neg := consumeSign(b) // consume sign + suffix, neg := consumeSign(b, false) // consume sign wholeBytes, fracBytes := bytesCutByte(suffix, '.', true) // consume whole and frac fields whole, okWhole := jsonwire.ParseUint(wholeBytes) // parse whole field; may overflow frac, okFrac := parseFracBase10(fracBytes, pow10) // parse frac field @@ -433,40 +439,161 @@ func parseDurationBase10(b []byte, pow10 uint64) (time.Duration, error) { } } -// appendDurationBase60 appends d formatted with H:MM:SS.SSS notation. -func appendDurationBase60(b []byte, d time.Duration) []byte { - b, n := mayAppendDurationSign(b, d) // append sign - n, nsec := bits.Div64(0, n, 1e9) // compute nsec field - n, sec := bits.Div64(0, n, 60) // compute sec field - hour, min := bits.Div64(0, n, 60) // compute hour and min fields - b = strconv.AppendUint(b, hour, 10) // append hour field - b = append(b, ':', '0'+byte(min/10), '0'+byte(min%10)) // append min field - b = append(b, ':', '0'+byte(sec/10), '0'+byte(sec%10)) // append sec field - return appendFracBase10(b, nsec, 1e9) // append nsec field +// appendDurationISO8601 appends an ISO 8601 duration with a restricted grammar, +// where leading and trailing zeroes and zero-value designators are omitted. +// It only uses hour, minute, and second designators since ISO 8601 defines +// those as being "accurate", while year, month, week, and day are "nominal". +func appendDurationISO8601(b []byte, d time.Duration) []byte { + if d == 0 { + return append(b, "PT0S"...) + } + b, n := mayAppendDurationSign(b, d) + b = append(b, "PT"...) + n, nsec := bits.Div64(0, n, 1e9) // compute nsec field + n, sec := bits.Div64(0, n, 60) // compute sec field + hour, min := bits.Div64(0, n, 60) // compute hour and min fields + if hour > 0 { + b = append(strconv.AppendUint(b, hour, 10), 'H') + } + if min > 0 { + b = append(strconv.AppendUint(b, min, 10), 'M') + } + if sec > 0 || nsec > 0 { + b = append(appendFracBase10(strconv.AppendUint(b, sec, 10), nsec, 1e9), 'S') + } + return b } -// parseDurationBase60 parses d formatted with H:MM:SS.SSS notation. -// The exact grammar is `-?(0|[1-9][0-9]*):[0-5][0-9]:[0-5][0-9]([.][0-9]+)?`. -func parseDurationBase60(b []byte) (time.Duration, error) { - checkBase60 := func(b []byte) bool { - return len(b) == 2 && ('0' <= b[0] && b[0] <= '5') && '0' <= b[1] && b[1] <= '9' - } - suffix, neg := consumeSign(b) // consume sign - hourBytes, suffix := bytesCutByte(suffix, ':', false) // consume hour field - minBytes, suffix := bytesCutByte(suffix, ':', false) // consume min field - secBytes, nsecBytes := bytesCutByte(suffix, '.', true) // consume sec and nsec fields - hour, okHour := jsonwire.ParseUint(hourBytes) // parse hour field; may overflow - min := parseDec2(minBytes) // parse min field - sec := parseDec2(secBytes) // parse sec field - nsec, okNsec := parseFracBase10(nsecBytes, 1e9) // parse nsec field - n := uint64(min)*60*1e9 + uint64(sec)*1e9 + uint64(nsec) // cannot overflow - hi, lo := bits.Mul64(hour, 60*60*1e9) // overflow if hi > 0 - sum, co := bits.Add64(lo, n, 0) // overflow if co > 0 - switch d := mayApplyDurationSign(sum, neg); { // overflow if neg != (d < 0) - case (!okHour && hour != math.MaxUint64) || !checkBase60(minBytes) || !checkBase60(secBytes) || !okNsec: - return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrSyntax) - case !okHour || hi > 0 || co > 0 || neg != (d < 0): - return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrRange) +// daysPerYear is the exact average number of days in a year according to +// the Gregorian calender, which has an extra day each year that is +// a multiple of 4, unless it is evenly divisible by 100 but not by 400. +// This does not take into account leap seconds, which are not deterministic. +const daysPerYear = 365.2425 + +var errInaccurateDateUnits = errors.New("inaccurate year, month, week, or day units") + +// parseDurationISO8601 parses a duration according to ISO 8601-1:2019, +// section 5.5.2.2 and 5.5.2.3 with the following restrictions or extensions: +// +// - A leading minus sign is permitted for negative duration according +// to ISO 8601-2:2019, section 4.4.1.9. We do not permit negative values +// for each "time scale component", which is permitted by section 4.4.1.1, +// but rarely supported by parsers. +// +// - A leading plus sign is permitted (and ignored). +// This is not required by ISO 8601, but not forbidden either. +// There is some precedent for this as it is supported by the principle of +// duration arithmetic as specified in ISO 8601-2-2019, section 14.1. +// Of note, the JavaScript grammar for ISO 8601 permits a leading plus sign. +// +// - A fractional value is only permitted for accurate units +// (i.e., hour, minute, and seconds) in the last time component, +// which is permissible by ISO 8601-1:2019, section 5.5.2.3. +// +// - Both periods ('.') and commas (',') are supported as the separator +// between the integer part and fraction part of a number, +// as specified in ISO 8601-1:2019, section 3.2.6. +// While ISO 8601 recommends comma as the default separator, +// most formatters uses a period. +// +// - Leading zeros are ignored. This is not required by ISO 8601, +// but also not forbidden by the standard. Many parsers support this. +// +// - Lowercase designators are supported. This is not required by ISO 8601, +// but also not forbidden by the standard. Many parsers support this. +// +// If the nominal units of year, month, week, or day are present, +// this produces a best-effort value and also reports [errInaccurateDateUnits]. +// +// The accepted grammar is identical to JavaScript's Duration: +// +// https://tc39.es/proposal-temporal/#prod-Duration +// +// We follow JavaScript's grammar as JSON itself is derived from JavaScript. +// The Temporal.Duration.toJSON method is guaranteed to produce an output +// that can be parsed by this function so long as arithmetic in JavaScript +// do not use a largestUnit value higher than "hours" (which is the default). +// Even if it does, this will do a best-effort parsing with inaccurate units, +// but report [errInaccurateDateUnits]. +func parseDurationISO8601(b []byte) (time.Duration, error) { + var invalid, overflow, inaccurate, sawFrac bool + var sumNanos, n, co uint64 + + // cutBytes is like [bytes.Cut], but uses either c0 or c1 as the separator. + cutBytes := func(b []byte, c0, c1 byte) (prefix, suffix []byte, ok bool) { + for i, c := range b { + if c == c0 || c == c1 { + return b[:i], b[i+1:], true + } + } + return b, nil, false + } + + // mayParseUnit attempts to parse another date or time number + // identified by the desHi and desLo unit characters. + // If the part is absent for current unit, it returns b as is. + mayParseUnit := func(b []byte, desHi, desLo byte, unit time.Duration) []byte { + number, suffix, ok := cutBytes(b, desHi, desLo) + if !ok || sawFrac { + return b // designator is not present or already saw fraction, which can only be in the last component + } + + // Parse the number. + // A fraction allowed for the accurate units in the last part. + whole, frac, ok := cutBytes(number, '.', ',') + if ok { + sawFrac = true + invalid = invalid || len(frac) == len("") || unit > time.Hour + if unit == time.Second { + n, ok = parsePaddedBase10(frac, uint64(time.Second)) + invalid = invalid || !ok + } else { + f, err := strconv.ParseFloat("0."+string(frac), 64) + invalid = invalid || err != nil || len(bytes.Trim(frac[len("."):], "0123456789")) > 0 + n = uint64(math.Round(f * float64(unit))) // never overflows since f is within [0..1] + } + sumNanos, co = bits.Add64(sumNanos, n, 0) // overflow if co > 0 + overflow = overflow || co > 0 + } + for len(whole) > 1 && whole[0] == '0' { + whole = whole[len("0"):] // trim leading zeros + } + n, ok := jsonwire.ParseUint(whole) // overflow if !ok && MaxUint64 + hi, lo := bits.Mul64(n, uint64(unit)) // overflow if hi > 0 + sumNanos, co = bits.Add64(sumNanos, lo, 0) // overflow if co > 0 + invalid = invalid || (!ok && n != math.MaxUint64) + overflow = overflow || (!ok && n == math.MaxUint64) || hi > 0 || co > 0 + inaccurate = inaccurate || unit > time.Hour + return suffix + } + + suffix, neg := consumeSign(b, true) + prefix, suffix, okP := cutBytes(suffix, 'P', 'p') + durDate, durTime, okT := cutBytes(suffix, 'T', 't') + invalid = invalid || len(prefix) > 0 || !okP || (okT && len(durTime) == 0) || len(durDate)+len(durTime) == 0 + if len(durDate) > 0 { // nominal portion of the duration + durDate = mayParseUnit(durDate, 'Y', 'y', time.Duration(daysPerYear*24*60*60*1e9)) + durDate = mayParseUnit(durDate, 'M', 'm', time.Duration(daysPerYear/12*24*60*60*1e9)) + durDate = mayParseUnit(durDate, 'W', 'w', time.Duration(7*24*60*60*1e9)) + durDate = mayParseUnit(durDate, 'D', 'd', time.Duration(24*60*60*1e9)) + invalid = invalid || len(durDate) > 0 // unknown elements + } + if len(durTime) > 0 { // accurate portion of the duration + durTime = mayParseUnit(durTime, 'H', 'h', time.Duration(60*60*1e9)) + durTime = mayParseUnit(durTime, 'M', 'm', time.Duration(60*1e9)) + durTime = mayParseUnit(durTime, 'S', 's', time.Duration(1e9)) + invalid = invalid || len(durTime) > 0 // unknown elements + } + d := mayApplyDurationSign(sumNanos, neg) + overflow = overflow || (neg != (d < 0) && d != 0) // overflows signed duration + + switch { + case invalid: + return 0, fmt.Errorf("invalid ISO 8601 duration %q: %w", b, strconv.ErrSyntax) + case overflow: + return 0, fmt.Errorf("invalid ISO 8601 duration %q: %w", b, strconv.ErrRange) + case inaccurate: + return d, fmt.Errorf("invalid ISO 8601 duration %q: %w", b, errInaccurateDateUnits) default: return d, nil } @@ -515,7 +642,7 @@ func appendTimeUnix(b []byte, t time.Time, pow10 uint64) []byte { // parseTimeUnix parses t formatted as a decimal fractional number, // where pow10 is a power-of-10 used to scale down the number. func parseTimeUnix(b []byte, pow10 uint64) (time.Time, error) { - suffix, neg := consumeSign(b) // consume sign + suffix, neg := consumeSign(b, false) // consume sign wholeBytes, fracBytes := bytesCutByte(suffix, '.', true) // consume whole and frac fields whole, okWhole := jsonwire.ParseUint(wholeBytes) // parse whole field; may overflow frac, okFrac := parseFracBase10(fracBytes, 1e9/pow10) // parse frac field @@ -614,10 +741,14 @@ func parsePaddedBase10(b []byte, max10 uint64) (n uint64, ok bool) { return n, true } -// consumeSign consumes an optional leading negative sign. -func consumeSign(b []byte) ([]byte, bool) { - if len(b) > 0 && b[0] == '-' { - return b[len("-"):], true +// consumeSign consumes an optional leading negative or positive sign. +func consumeSign(b []byte, allowPlus bool) ([]byte, bool) { + if len(b) > 0 { + if b[0] == '-' { + return b[len("-"):], true + } else if b[0] == '+' && allowPlus { + return b[len("+"):], false + } } return b, false } diff --git a/vendor/github.com/go-json-experiment/json/doc.go b/vendor/github.com/go-json-experiment/json/doc.go index 886e0480b64..a4631685890 100644 --- a/vendor/github.com/go-json-experiment/json/doc.go +++ b/vendor/github.com/go-json-experiment/json/doc.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + // Package json implements semantic processing of JSON as specified in RFC 8259. // JSON is a simple data interchange format that can represent // primitive data types such as booleans, strings, and numbers, @@ -159,6 +161,100 @@ // Marshaling or unmarshaling a non-empty struct // without any JSON representable fields results in a [SemanticError]. // Unexported fields must not have any `json` tags except for `json:"-"`. +// +// # Security Considerations +// +// JSON is frequently used as a data interchange format to communicate +// between different systems, possibly implemented in different languages. +// For interoperability and security reasons, it is important that +// all implementations agree upon the semantic meaning of the data. +// +// [For example, suppose we have two micro-services.] +// The first service is responsible for authenticating a JSON request, +// while the second service is responsible for executing the request +// (having assumed that the prior service authenticated the request). +// If an attacker were able to maliciously craft a JSON request such that +// both services believe that the same request is from different users, +// it could bypass the authenticator with valid credentials for one user, +// but maliciously perform an action on behalf of a different user. +// +// According to RFC 8259, there unfortunately exist many JSON texts +// that are syntactically valid but semantically ambiguous. +// For example, the standard does not define how to interpret duplicate +// names within an object. +// +// The v1 [encoding/json] and [encoding/json/v2] packages +// interpret some inputs in different ways. In particular: +// +// - The standard specifies that JSON must be encoded using UTF-8. +// By default, v1 replaces invalid bytes of UTF-8 in JSON strings +// with the Unicode replacement character, +// while v2 rejects inputs with invalid UTF-8. +// To change the default, specify the [jsontext.AllowInvalidUTF8] option. +// The replacement of invalid UTF-8 is a form of data corruption +// that alters the precise meaning of strings. +// +// - The standard does not specify a particular behavior when +// duplicate names are encountered within a JSON object, +// which means that different implementations may behave differently. +// By default, v1 allows for the presence of duplicate names, +// while v2 rejects duplicate names. +// To change the default, specify the [jsontext.AllowDuplicateNames] option. +// If allowed, object members are processed in the order they are observed, +// meaning that later values will replace or be merged into prior values, +// depending on the Go value type. +// +// - The standard defines a JSON object as an unordered collection of name/value pairs. +// While ordering can be observed through the underlying [jsontext] API, +// both v1 and v2 generally avoid exposing the ordering. +// No application should semantically depend on the order of object members. +// Allowing duplicate names is a vector through which ordering of members +// can accidentally be observed and depended upon. +// +// - The standard suggests that JSON object names are typically compared +// based on equality of the sequence of Unicode code points, +// which implies that comparing names is often case-sensitive. +// When unmarshaling a JSON object into a Go struct, +// by default, v1 uses a (loose) case-insensitive match on the name, +// while v2 uses a (strict) case-sensitive match on the name. +// To change the default, specify the [MatchCaseInsensitiveNames] option. +// The use of case-insensitive matching provides another vector through +// which duplicate names can occur. Allowing case-insensitive matching +// means that v1 or v2 might interpret JSON objects differently from most +// other JSON implementations (which typically use a case-sensitive match). +// +// - The standard does not specify a particular behavior when +// an unknown name in a JSON object is encountered. +// When unmarshaling a JSON object into a Go struct, by default +// both v1 and v2 ignore unknown names and their corresponding values. +// To change the default, specify the [RejectUnknownMembers] option. +// +// - The standard suggests that implementations may use a float64 +// to represent a JSON number. Consequently, large JSON integers +// may lose precision when stored as a floating-point type. +// Both v1 and v2 correctly preserve precision when marshaling and +// unmarshaling a concrete integer type. However, even if v1 and v2 +// preserve precision for concrete types, other JSON implementations +// may not be able to preserve precision for outputs produced by v1 or v2. +// The `string` tag option can be used to specify that an integer type +// is to be quoted within a JSON string to avoid loss of precision. +// Furthermore, v1 and v2 may still lose precision when unmarshaling +// into an any interface value, where unmarshal uses a float64 +// by default to represent a JSON number. +// To change the default, specify the [WithUnmarshalers] option +// with a custom unmarshaler that pre-populates the interface value +// with a concrete Go type that can preserve precision. +// +// RFC 8785 specifies a canonical form for any JSON text, +// which explicitly defines specific behaviors that RFC 8259 leaves undefined. +// In theory, if a text can successfully [jsontext.Value.Canonicalize] +// without changing the semantic meaning of the data, then it provides a +// greater degree of confidence that the data is more secure and interoperable. +// +// The v2 API generally chooses more secure defaults than v1, +// but care should still be taken with large integers or unknown members. +// +// [For example, suppose we have two micro-services.]: https://www.youtube.com/watch?v=avilmOcHKHE&t=1057s package json // requireKeyedLiterals can be embedded in a struct to require keyed literals. diff --git a/vendor/github.com/go-json-experiment/json/errors.go b/vendor/github.com/go-json-experiment/json/errors.go index 6460ab50efe..da17861d13b 100644 --- a/vendor/github.com/go-json-experiment/json/errors.go +++ b/vendor/github.com/go-json-experiment/json/errors.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -60,6 +62,11 @@ func isFatalError(err error, flags jsonflags.Flags) bool { // SemanticError describes an error determining the meaning // of JSON data as Go data or vice-versa. // +// If a [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom] method +// returns a SemanticError when called by the [json] package, +// then the ByteOffset, JSONPointer, and GoType fields are automatically +// populated by the calling context if they are the zero value. +// // The contents of this error as produced by this package may change over time. type SemanticError struct { requireKeyedLiterals @@ -86,7 +93,10 @@ type SemanticError struct { } // coder is implemented by [jsontext.Encoder] or [jsontext.Decoder]. -type coder interface{ StackPointer() jsontext.Pointer } +type coder interface { + StackPointer() jsontext.Pointer + Options() Options +} // newInvalidFormatError wraps err in a SemanticError because // the current type t cannot handle the provided options format. @@ -95,13 +105,13 @@ type coder interface{ StackPointer() jsontext.Pointer } // If [jsonflags.ReportErrorsWithLegacySemantics] is specified, // then this automatically skips the next value when unmarshaling // to ensure that the value is fully consumed. -func newInvalidFormatError(c coder, t reflect.Type, o *jsonopts.Struct) error { - err := fmt.Errorf("invalid format flag %q", o.Format) +func newInvalidFormatError(c coder, t reflect.Type) error { + err := fmt.Errorf("invalid format flag %q", c.Options().(*jsonopts.Struct).Format) switch c := c.(type) { case *jsontext.Encoder: err = newMarshalErrorBefore(c, t, err) case *jsontext.Decoder: - err = newUnmarshalErrorBeforeWithSkipping(c, o, t, err) + err = newUnmarshalErrorBeforeWithSkipping(c, t, err) } return err } @@ -118,18 +128,25 @@ func newMarshalErrorBefore(e *jsontext.Encoder, t reflect.Type, err error) error // is positioned right before the next token or value, which causes an error. // It does not record the next JSON kind as this error is used to indicate // the receiving Go value is invalid to unmarshal into (and not a JSON error). +// However, if [jsonflags.ReportErrorsWithLegacySemantics] is specified, +// then it does record the next JSON kind for historical reporting reasons. func newUnmarshalErrorBefore(d *jsontext.Decoder, t reflect.Type, err error) error { + var k jsontext.Kind + if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + k = d.PeekKind() + } return &SemanticError{action: "unmarshal", GoType: t, Err: err, ByteOffset: d.InputOffset() + int64(export.Decoder(d).CountNextDelimWhitespace()), - JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, +1))} + JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, +1)), + JSONKind: k} } // newUnmarshalErrorBeforeWithSkipping is like [newUnmarshalErrorBefore], // but automatically skips the next value if // [jsonflags.ReportErrorsWithLegacySemantics] is specified. -func newUnmarshalErrorBeforeWithSkipping(d *jsontext.Decoder, o *jsonopts.Struct, t reflect.Type, err error) error { +func newUnmarshalErrorBeforeWithSkipping(d *jsontext.Decoder, t reflect.Type, err error) error { err = newUnmarshalErrorBefore(d, t, err) - if o.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { if err2 := export.Decoder(d).SkipValue(); err2 != nil { return err2 } @@ -161,9 +178,9 @@ func newUnmarshalErrorAfterWithValue(d *jsontext.Decoder, t reflect.Type, err er // newUnmarshalErrorAfterWithSkipping is like [newUnmarshalErrorAfter], // but automatically skips the remainder of the current value if // [jsonflags.ReportErrorsWithLegacySemantics] is specified. -func newUnmarshalErrorAfterWithSkipping(d *jsontext.Decoder, o *jsonopts.Struct, t reflect.Type, err error) error { +func newUnmarshalErrorAfterWithSkipping(d *jsontext.Decoder, t reflect.Type, err error) error { err = newUnmarshalErrorAfter(d, t, err) - if o.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { if err2 := export.Decoder(d).SkipValueRemainder(); err2 != nil { return err2 } diff --git a/vendor/github.com/go-json-experiment/json/fields.go b/vendor/github.com/go-json-experiment/json/fields.go index 082f32036f2..a164f00e2c3 100644 --- a/vendor/github.com/go-json-experiment/json/fields.go +++ b/vendor/github.com/go-json-experiment/json/fields.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -402,6 +404,7 @@ type fieldOptions struct { // the JSON member name and other features. func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, err error) { tag, hasTag := sf.Tag.Lookup("json") + tagOrig := tag // Check whether this field is explicitly ignored. if tag == "-" { @@ -451,6 +454,13 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, err = cmp.Or(err, fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, name)) name = string([]rune(name)) // replace invalid UTF-8 with utf8.RuneError } + if name == "-" && tag[0] == '-' { + defer func() { // defer to let other errors take precedence + err = cmp.Or(err, fmt.Errorf("Go struct field %s has JSON object name %q; either "+ + "use `json:\"-\"` to ignore the field or "+ + "use `json:\"'-'%s` to specify %q as the name", sf.Name, out.name, strings.TrimPrefix(strconv.Quote(tagOrig), `"-`), name)) + }() + } if err2 == nil { out.hasName = true out.name = name diff --git a/vendor/github.com/go-json-experiment/json/fold.go b/vendor/github.com/go-json-experiment/json/fold.go index 9ab735814cf..973f52e73a4 100644 --- a/vendor/github.com/go-json-experiment/json/fold.go +++ b/vendor/github.com/go-json-experiment/json/fold.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( diff --git a/vendor/github.com/go-json-experiment/json/intern.go b/vendor/github.com/go-json-experiment/json/intern.go index 42fc3d47191..1bfb8ca633a 100644 --- a/vendor/github.com/go-json-experiment/json/intern.go +++ b/vendor/github.com/go-json-experiment/json/intern.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( diff --git a/vendor/github.com/go-json-experiment/json/internal/internal.go b/vendor/github.com/go-json-experiment/json/internal/internal.go index bb36b035d11..00b43fa3075 100644 --- a/vendor/github.com/go-json-experiment/json/internal/internal.go +++ b/vendor/github.com/go-json-experiment/json/internal/internal.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package internal import "errors" @@ -19,6 +21,7 @@ var AllowInternalUse NotForPublicUse var ( ErrCycle = errors.New("encountered a cycle") ErrNonNilReference = errors.New("value must be passed as a non-nil pointer reference") + ErrNilInterface = errors.New("cannot derive concrete type for nil interface with finite type set") ) var ( diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go b/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go index d9cad6eeb2f..a22db546d09 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + // jsonflags implements all the optional boolean flags. // These flags are shared across both "json", "jsontext", and "jsonopts". package jsonflags @@ -50,18 +52,20 @@ const ( AllowInvalidUTF8 | EscapeForHTML | EscapeForJS | - EscapeInvalidUTF8 | PreserveRawStrings | Deterministic | FormatNilMapAsNull | FormatNilSliceAsNull | MatchCaseInsensitiveNames | CallMethodsWithLegacySemantics | + FormatByteArrayAsArray | FormatBytesWithLegacySemantics | - FormatTimeWithLegacySemantics | + FormatDurationAsNano | MatchCaseSensitiveDelimiter | MergeWithLegacySemantics | - OmitEmptyWithLegacyDefinition | + OmitEmptyWithLegacySemantics | + ParseBytesWithLooseRFC4648 | + ParseTimeWithLooseRFC3339 | ReportErrorsWithLegacySemantics | StringifyWithLegacySemantics | UnmarshalArrayFromAnyLength @@ -75,7 +79,7 @@ const ( WhitespaceFlags = AnyWhitespace | Indent | IndentPrefix // AnyEscape is the set of flags related to escaping in a JSON string. - AnyEscape = EscapeForHTML | EscapeForJS | EscapeInvalidUTF8 + AnyEscape = EscapeForHTML | EscapeForJS // CanonicalizeNumbers is the set of flags related to raw number canonicalization. CanonicalizeNumbers = CanonicalizeRawInts | CanonicalizeRawFloats @@ -95,7 +99,6 @@ const ( ReorderRawObjects // encode only EscapeForHTML // encode only EscapeForJS // encode only - EscapeInvalidUTF8 // encode only; only exposed in v1 Multiline // encode only SpaceAfterColon // encode only SpaceAfterComma // encode only @@ -130,11 +133,14 @@ const ( _ Bools = (maxArshalV2Flag >> 1) << iota CallMethodsWithLegacySemantics // marshal or unmarshal + FormatByteArrayAsArray // marshal or unmarshal FormatBytesWithLegacySemantics // marshal or unmarshal - FormatTimeWithLegacySemantics // marshal or unmarshal + FormatDurationAsNano // marshal or unmarshal MatchCaseSensitiveDelimiter // marshal or unmarshal MergeWithLegacySemantics // unmarshal - OmitEmptyWithLegacyDefinition // marshal + OmitEmptyWithLegacySemantics // marshal + ParseBytesWithLooseRFC4648 // unmarshal + ParseTimeWithLooseRFC3339 // unmarshal ReportErrorsWithLegacySemantics // marshal or unmarshal StringifyWithLegacySemantics // marshal or unmarshal StringifyBoolsAndStrings // marshal or unmarshal; for internal use by jsonv2.makeStructArshaler @@ -144,6 +150,12 @@ const ( maxArshalV1Flag ) +// bitsUsed is the number of bits used in the 64-bit boolean flags +const bitsUsed = 42 + +// Static compile check that bitsUsed and maxArshalV1Flag are in sync. +const _ = uint64((1< 0b_110_11011 dst.Values &= ^src.Presence // e.g., 0b_1000_0011 & 0b_1010_0101 -> 0b_100_00001 dst.Values |= src.Values // e.g., 0b_1000_0001 | 0b_1001_0010 -> 0b_100_10011 @@ -170,7 +182,7 @@ func (fs *Flags) Set(f Bools) { // then set the presence for all the identifier bits (using OR), // then invert the identifier bits to clear out the values (using AND-NOT), // then copy over all the identifier bits to the value if LSB is 1. - // e.g., fs := Flags{Presence: 0b_0101_0010, Value: 0b_0001_0010} + // e.g., fs := Flags{Presence: 0b_0101_0010, Values: 0b_0001_0010} // e.g., f := 0b_1001_0001 id := uint64(f) &^ uint64(1) // e.g., 0b_1001_0001 & 0b_1111_1110 -> 0b_1001_0000 fs.Presence |= id // e.g., 0b_0101_0010 | 0b_1001_0000 -> 0b_1101_0011 @@ -195,7 +207,7 @@ func (fs Flags) Has(f Bools) bool { // The value bit of f (i.e., the LSB) is ignored. func (fs *Flags) Clear(f Bools) { // Invert f to produce a mask to clear all bits in f (using AND). - // e.g., fs := Flags{Presence: 0b_0101_0010, Value: 0b_0001_0010} + // e.g., fs := Flags{Presence: 0b_0101_0010, Values: 0b_0001_0010} // e.g., f := 0b_0001_1000 mask := uint64(^f) // e.g., 0b_0001_1000 -> 0b_1110_0111 fs.Presence &= mask // e.g., 0b_0101_0010 & 0b_1110_0111 -> 0b_0100_0010 diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go b/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go index c23c280df99..f0bd67844a6 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsonopts import ( @@ -59,22 +61,11 @@ var DefaultOptionsV1 = Struct{ }, } -// CopyCoderOptions copies coder-specific options from src to dst. -// This is used by json.MarshalEncode and json.UnmarshalDecode since those -// functions ignore any coder-specific options and uses the options from the -// Encoder or Decoder that is passed in. -func (dst *Struct) CopyCoderOptions(src *Struct) { - srcFlags := src.Flags - srcFlags.Clear(^jsonflags.AllCoderFlags) - dst.Flags.Join(srcFlags) - dst.CoderValues = src.CoderValues -} - func (*Struct) JSONOptions(internal.NotForPublicUse) {} // GetUnknownOption is injected by the "json" package to handle Options // declared in that package so that "jsonopts" can handle them. -var GetUnknownOption = func(*Struct, Options) (any, bool) { panic("unknown option") } +var GetUnknownOption = func(Struct, Options) (any, bool) { panic("unknown option") } func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { // Collapse the options to *Struct to simplify lookup. @@ -113,62 +104,85 @@ func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { } return any(structOpts.DepthLimit).(T), true default: - v, ok := GetUnknownOption(structOpts, opt) + v, ok := GetUnknownOption(*structOpts, opt) return v.(T), ok } } // JoinUnknownOption is injected by the "json" package to handle Options // declared in that package so that "jsonopts" can handle them. -var JoinUnknownOption = func(*Struct, Options) { panic("unknown option") } +var JoinUnknownOption = func(Struct, Options) Struct { panic("unknown option") } func (dst *Struct) Join(srcs ...Options) { + dst.join(false, srcs...) +} + +func (dst *Struct) JoinWithoutCoderOptions(srcs ...Options) { + dst.join(true, srcs...) +} + +func (dst *Struct) join(excludeCoderOptions bool, srcs ...Options) { for _, src := range srcs { switch src := src.(type) { case nil: continue case jsonflags.Bools: + if excludeCoderOptions { + src &= ^jsonflags.AllCoderFlags + } dst.Flags.Set(src) case Indent: + if excludeCoderOptions { + continue + } dst.Flags.Set(jsonflags.Multiline | jsonflags.Indent | 1) dst.Indent = string(src) case IndentPrefix: + if excludeCoderOptions { + continue + } dst.Flags.Set(jsonflags.Multiline | jsonflags.IndentPrefix | 1) dst.IndentPrefix = string(src) case ByteLimit: + if excludeCoderOptions { + continue + } dst.Flags.Set(jsonflags.ByteLimit | 1) dst.ByteLimit = int64(src) case DepthLimit: + if excludeCoderOptions { + continue + } dst.Flags.Set(jsonflags.DepthLimit | 1) dst.DepthLimit = int(src) case *Struct: - dst.Flags.Join(src.Flags) - if src.Flags.Has(jsonflags.NonBooleanFlags) { - if src.Flags.Has(jsonflags.Indent) { + srcFlags := src.Flags // shallow copy the flags + if excludeCoderOptions { + srcFlags.Clear(jsonflags.AllCoderFlags) + } + dst.Flags.Join(srcFlags) + if srcFlags.Has(jsonflags.NonBooleanFlags) { + if srcFlags.Has(jsonflags.Indent) { dst.Indent = src.Indent } - if src.Flags.Has(jsonflags.IndentPrefix) { + if srcFlags.Has(jsonflags.IndentPrefix) { dst.IndentPrefix = src.IndentPrefix } - if src.Flags.Has(jsonflags.ByteLimit) { + if srcFlags.Has(jsonflags.ByteLimit) { dst.ByteLimit = src.ByteLimit } - if src.Flags.Has(jsonflags.DepthLimit) { + if srcFlags.Has(jsonflags.DepthLimit) { dst.DepthLimit = src.DepthLimit } - if src.Flags.Has(jsonflags.Marshalers) { + if srcFlags.Has(jsonflags.Marshalers) { dst.Marshalers = src.Marshalers } - if src.Flags.Has(jsonflags.Unmarshalers) { + if srcFlags.Has(jsonflags.Unmarshalers) { dst.Unmarshalers = src.Unmarshalers } } - if src.Format != "" { - dst.Format = src.Format - dst.FormatDepth = src.FormatDepth - } default: - JoinUnknownOption(dst, src) + *dst = JoinUnknownOption(*dst, src) } } } diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go b/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go index 02787719ca3..6a5acb8ec09 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsonwire import ( diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go b/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go index fb4c50da6c0..2dc4bc6fcf0 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsonwire import ( @@ -90,11 +92,7 @@ func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes, flags *jsonflag case isInvalidUTF8(r, rn): hasInvalidUTF8 = true dst = append(dst, src[i:n-rn]...) - if flags.Get(jsonflags.EscapeInvalidUTF8) { - dst = append(dst, `\ufffd`...) - } else { - dst = append(dst, "\ufffd"...) - } + dst = append(dst, "\ufffd"...) i = n case (r == '\u2028' || r == '\u2029') && flags.Get(jsonflags.EscapeForJS): dst = append(dst, src[i:n-rn]...) diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go b/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go index 1831a66bdee..a0622c65b81 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + // Package jsonwire implements stateless functionality for handling JSON text. package jsonwire diff --git a/vendor/github.com/go-json-experiment/json/jsontext/alias.go b/vendor/github.com/go-json-experiment/json/jsontext/alias.go new file mode 100644 index 00000000000..dc18d5d55df --- /dev/null +++ b/vendor/github.com/go-json-experiment/json/jsontext/alias.go @@ -0,0 +1,536 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by alias_gen.go; DO NOT EDIT. + +//go:build goexperiment.jsonv2 && go1.25 + +// Package jsontext implements syntactic processing of JSON +// as specified in RFC 4627, RFC 7159, RFC 7493, RFC 8259, and RFC 8785. +// JSON is a simple data interchange format that can represent +// primitive data types such as booleans, strings, and numbers, +// in addition to structured data types such as objects and arrays. +// +// The [Encoder] and [Decoder] types are used to encode or decode +// a stream of JSON tokens or values. +// +// # Tokens and Values +// +// A JSON token refers to the basic structural elements of JSON: +// +// - a JSON literal (i.e., null, true, or false) +// - a JSON string (e.g., "hello, world!") +// - a JSON number (e.g., 123.456) +// - a begin or end delimiter for a JSON object (i.e., '{' or '}') +// - a begin or end delimiter for a JSON array (i.e., '[' or ']') +// +// A JSON token is represented by the [Token] type in Go. Technically, +// there are two additional structural characters (i.e., ':' and ','), +// but there is no [Token] representation for them since their presence +// can be inferred by the structure of the JSON grammar itself. +// For example, there must always be an implicit colon between +// the name and value of a JSON object member. +// +// A JSON value refers to a complete unit of JSON data: +// +// - a JSON literal, string, or number +// - a JSON object (e.g., `{"name":"value"}`) +// - a JSON array (e.g., `[1,2,3,]`) +// +// A JSON value is represented by the [Value] type in Go and is a []byte +// containing the raw textual representation of the value. There is some overlap +// between tokens and values as both contain literals, strings, and numbers. +// However, only a value can represent the entirety of a JSON object or array. +// +// The [Encoder] and [Decoder] types contain methods to read or write the next +// [Token] or [Value] in a sequence. They maintain a state machine to validate +// whether the sequence of JSON tokens and/or values produces a valid JSON. +// [Options] may be passed to the [NewEncoder] or [NewDecoder] constructors +// to configure the syntactic behavior of encoding and decoding. +// +// # Terminology +// +// The terms "encode" and "decode" are used for syntactic functionality +// that is concerned with processing JSON based on its grammar, and +// the terms "marshal" and "unmarshal" are used for semantic functionality +// that determines the meaning of JSON values as Go values and vice-versa. +// This package (i.e., [jsontext]) deals with JSON at a syntactic layer, +// while [encoding/json/v2] deals with JSON at a semantic layer. +// The goal is to provide a clear distinction between functionality that +// is purely concerned with encoding versus that of marshaling. +// For example, one can directly encode a stream of JSON tokens without +// needing to marshal a concrete Go value representing them. +// Similarly, one can decode a stream of JSON tokens without +// needing to unmarshal them into a concrete Go value. +// +// This package uses JSON terminology when discussing JSON, which may differ +// from related concepts in Go or elsewhere in computing literature. +// +// - a JSON "object" refers to an unordered collection of name/value members. +// - a JSON "array" refers to an ordered sequence of elements. +// - a JSON "value" refers to either a literal (i.e., null, false, or true), +// string, number, object, or array. +// +// See RFC 8259 for more information. +// +// # Specifications +// +// Relevant specifications include RFC 4627, RFC 7159, RFC 7493, RFC 8259, +// and RFC 8785. Each RFC is generally a stricter subset of another RFC. +// In increasing order of strictness: +// +// - RFC 4627 and RFC 7159 do not require (but recommend) the use of UTF-8 +// and also do not require (but recommend) that object names be unique. +// - RFC 8259 requires the use of UTF-8, +// but does not require (but recommends) that object names be unique. +// - RFC 7493 requires the use of UTF-8 +// and also requires that object names be unique. +// - RFC 8785 defines a canonical representation. It requires the use of UTF-8 +// and also requires that object names be unique and in a specific ordering. +// It specifies exactly how strings and numbers must be formatted. +// +// The primary difference between RFC 4627 and RFC 7159 is that the former +// restricted top-level values to only JSON objects and arrays, while +// RFC 7159 and subsequent RFCs permit top-level values to additionally be +// JSON nulls, booleans, strings, or numbers. +// +// By default, this package operates on RFC 7493, but can be configured +// to operate according to the other RFC specifications. +// RFC 7493 is a stricter subset of RFC 8259 and fully compliant with it. +// In particular, it makes specific choices about behavior that RFC 8259 +// leaves as undefined in order to ensure greater interoperability. +// +// # Security Considerations +// +// See the "Security Considerations" section in [encoding/json/v2]. +package jsontext + +import ( + "encoding/json/jsontext" + "io" +) + +// Decoder is a streaming decoder for raw JSON tokens and values. +// It is used to read a stream of top-level JSON values, +// each separated by optional whitespace characters. +// +// [Decoder.ReadToken] and [Decoder.ReadValue] calls may be interleaved. +// For example, the following JSON value: +// +// {"name":"value","array":[null,false,true,3.14159],"object":{"k":"v"}} +// +// can be parsed with the following calls (ignoring errors for brevity): +// +// d.ReadToken() // { +// d.ReadToken() // "name" +// d.ReadToken() // "value" +// d.ReadValue() // "array" +// d.ReadToken() // [ +// d.ReadToken() // null +// d.ReadToken() // false +// d.ReadValue() // true +// d.ReadToken() // 3.14159 +// d.ReadToken() // ] +// d.ReadValue() // "object" +// d.ReadValue() // {"k":"v"} +// d.ReadToken() // } +// +// The above is one of many possible sequence of calls and +// may not represent the most sensible method to call for any given token/value. +// For example, it is probably more common to call [Decoder.ReadToken] to obtain a +// string token for object names. +type Decoder = jsontext.Decoder + +// NewDecoder constructs a new streaming decoder reading from r. +// +// If r is a [bytes.Buffer], then the decoder parses directly from the buffer +// without first copying the contents to an intermediate buffer. +// Additional writes to the buffer must not occur while the decoder is in use. +func NewDecoder(r io.Reader, opts ...Options) *Decoder { + return jsontext.NewDecoder(r, opts...) +} + +// Encoder is a streaming encoder from raw JSON tokens and values. +// It is used to write a stream of top-level JSON values, +// each terminated with a newline character. +// +// [Encoder.WriteToken] and [Encoder.WriteValue] calls may be interleaved. +// For example, the following JSON value: +// +// {"name":"value","array":[null,false,true,3.14159],"object":{"k":"v"}} +// +// can be composed with the following calls (ignoring errors for brevity): +// +// e.WriteToken(BeginObject) // { +// e.WriteToken(String("name")) // "name" +// e.WriteToken(String("value")) // "value" +// e.WriteValue(Value(`"array"`)) // "array" +// e.WriteToken(BeginArray) // [ +// e.WriteToken(Null) // null +// e.WriteToken(False) // false +// e.WriteValue(Value("true")) // true +// e.WriteToken(Float(3.14159)) // 3.14159 +// e.WriteToken(EndArray) // ] +// e.WriteValue(Value(`"object"`)) // "object" +// e.WriteValue(Value(`{"k":"v"}`)) // {"k":"v"} +// e.WriteToken(EndObject) // } +// +// The above is one of many possible sequence of calls and +// may not represent the most sensible method to call for any given token/value. +// For example, it is probably more common to call [Encoder.WriteToken] with a string +// for object names. +type Encoder = jsontext.Encoder + +// NewEncoder constructs a new streaming encoder writing to w +// configured with the provided options. +// It flushes the internal buffer when the buffer is sufficiently full or +// when a top-level value has been written. +// +// If w is a [bytes.Buffer], then the encoder appends directly into the buffer +// without copying the contents from an intermediate buffer. +func NewEncoder(w io.Writer, opts ...Options) *Encoder { + return jsontext.NewEncoder(w, opts...) +} + +// SyntacticError is a description of a syntactic error that occurred when +// encoding or decoding JSON according to the grammar. +// +// The contents of this error as produced by this package may change over time. +type SyntacticError = jsontext.SyntacticError + +// Options configures [NewEncoder], [Encoder.Reset], [NewDecoder], +// and [Decoder.Reset] with specific features. +// Each function takes in a variadic list of options, where properties +// set in latter options override the value of previously set properties. +// +// There is a single Options type, which is used with both encoding and decoding. +// Some options affect both operations, while others only affect one operation: +// +// - [AllowDuplicateNames] affects encoding and decoding +// - [AllowInvalidUTF8] affects encoding and decoding +// - [EscapeForHTML] affects encoding only +// - [EscapeForJS] affects encoding only +// - [PreserveRawStrings] affects encoding only +// - [CanonicalizeRawInts] affects encoding only +// - [CanonicalizeRawFloats] affects encoding only +// - [ReorderRawObjects] affects encoding only +// - [SpaceAfterColon] affects encoding only +// - [SpaceAfterComma] affects encoding only +// - [Multiline] affects encoding only +// - [WithIndent] affects encoding only +// - [WithIndentPrefix] affects encoding only +// +// Options that do not affect a particular operation are ignored. +// +// The Options type is identical to [encoding/json.Options] and +// [encoding/json/v2.Options]. Options from the other packages may +// be passed to functionality in this package, but are ignored. +// Options from this package may be used with the other packages. +type Options = jsontext.Options + +// AllowDuplicateNames specifies that JSON objects may contain +// duplicate member names. Disabling the duplicate name check may provide +// performance benefits, but breaks compliance with RFC 7493, section 2.3. +// The input or output will still be compliant with RFC 8259, +// which leaves the handling of duplicate names as unspecified behavior. +// +// This affects either encoding or decoding. +func AllowDuplicateNames(v bool) Options { + return jsontext.AllowDuplicateNames(v) +} + +// AllowInvalidUTF8 specifies that JSON strings may contain invalid UTF-8, +// which will be mangled as the Unicode replacement character, U+FFFD. +// This causes the encoder or decoder to break compliance with +// RFC 7493, section 2.1, and RFC 8259, section 8.1. +// +// This affects either encoding or decoding. +func AllowInvalidUTF8(v bool) Options { + return jsontext.AllowInvalidUTF8(v) +} + +// EscapeForHTML specifies that '<', '>', and '&' characters within JSON strings +// should be escaped as a hexadecimal Unicode codepoint (e.g., \u003c) so that +// the output is safe to embed within HTML. +// +// This only affects encoding and is ignored when decoding. +func EscapeForHTML(v bool) Options { + return jsontext.EscapeForHTML(v) +} + +// EscapeForJS specifies that U+2028 and U+2029 characters within JSON strings +// should be escaped as a hexadecimal Unicode codepoint (e.g., \u2028) so that +// the output is valid to embed within JavaScript. See RFC 8259, section 12. +// +// This only affects encoding and is ignored when decoding. +func EscapeForJS(v bool) Options { + return jsontext.EscapeForJS(v) +} + +// PreserveRawStrings specifies that when encoding a raw JSON string in a +// [Token] or [Value], pre-escaped sequences +// in a JSON string are preserved to the output. +// However, raw strings still respect [EscapeForHTML] and [EscapeForJS] +// such that the relevant characters are escaped. +// If [AllowInvalidUTF8] is enabled, bytes of invalid UTF-8 +// are preserved to the output. +// +// This only affects encoding and is ignored when decoding. +func PreserveRawStrings(v bool) Options { + return jsontext.PreserveRawStrings(v) +} + +// CanonicalizeRawInts specifies that when encoding a raw JSON +// integer number (i.e., a number without a fraction and exponent) in a +// [Token] or [Value], the number is canonicalized +// according to RFC 8785, section 3.2.2.3. As a special case, +// the number -0 is canonicalized as 0. +// +// JSON numbers are treated as IEEE 754 double precision numbers. +// Any numbers with precision beyond what is representable by that form +// will lose their precision when canonicalized. For example, +// integer values beyond ±2⁵³ will lose their precision. +// For example, 1234567890123456789 is formatted as 1234567890123456800. +// +// This only affects encoding and is ignored when decoding. +func CanonicalizeRawInts(v bool) Options { + return jsontext.CanonicalizeRawInts(v) +} + +// CanonicalizeRawFloats specifies that when encoding a raw JSON +// floating-point number (i.e., a number with a fraction or exponent) in a +// [Token] or [Value], the number is canonicalized +// according to RFC 8785, section 3.2.2.3. As a special case, +// the number -0 is canonicalized as 0. +// +// JSON numbers are treated as IEEE 754 double precision numbers. +// It is safe to canonicalize a serialized single precision number and +// parse it back as a single precision number and expect the same value. +// If a number exceeds ±1.7976931348623157e+308, which is the maximum +// finite number, then it saturated at that value and formatted as such. +// +// This only affects encoding and is ignored when decoding. +func CanonicalizeRawFloats(v bool) Options { + return jsontext.CanonicalizeRawFloats(v) +} + +// ReorderRawObjects specifies that when encoding a raw JSON object in a +// [Value], the object members are reordered according to +// RFC 8785, section 3.2.3. +// +// This only affects encoding and is ignored when decoding. +func ReorderRawObjects(v bool) Options { + return jsontext.ReorderRawObjects(v) +} + +// SpaceAfterColon specifies that the JSON output should emit a space character +// after each colon separator following a JSON object name. +// If false, then no space character appears after the colon separator. +// +// This only affects encoding and is ignored when decoding. +func SpaceAfterColon(v bool) Options { + return jsontext.SpaceAfterColon(v) +} + +// SpaceAfterComma specifies that the JSON output should emit a space character +// after each comma separator following a JSON object value or array element. +// If false, then no space character appears after the comma separator. +// +// This only affects encoding and is ignored when decoding. +func SpaceAfterComma(v bool) Options { + return jsontext.SpaceAfterComma(v) +} + +// Multiline specifies that the JSON output should expand to multiple lines, +// where every JSON object member or JSON array element appears on +// a new, indented line according to the nesting depth. +// +// If [SpaceAfterColon] is not specified, then the default is true. +// If [SpaceAfterComma] is not specified, then the default is false. +// If [WithIndent] is not specified, then the default is "\t". +// +// If set to false, then the output is a single-line, +// where the only whitespace emitted is determined by the current +// values of [SpaceAfterColon] and [SpaceAfterComma]. +// +// This only affects encoding and is ignored when decoding. +func Multiline(v bool) Options { + return jsontext.Multiline(v) +} + +// WithIndent specifies that the encoder should emit multiline output +// where each element in a JSON object or array begins on a new, indented line +// beginning with the indent prefix (see [WithIndentPrefix]) +// followed by one or more copies of indent according to the nesting depth. +// The indent must only be composed of space or tab characters. +// +// If the intent to emit indented output without a preference for +// the particular indent string, then use [Multiline] instead. +// +// This only affects encoding and is ignored when decoding. +// Use of this option implies [Multiline] being set to true. +func WithIndent(indent string) Options { + return jsontext.WithIndent(indent) +} + +// WithIndentPrefix specifies that the encoder should emit multiline output +// where each element in a JSON object or array begins on a new, indented line +// beginning with the indent prefix followed by one or more copies of indent +// (see [WithIndent]) according to the nesting depth. +// The prefix must only be composed of space or tab characters. +// +// This only affects encoding and is ignored when decoding. +// Use of this option implies [Multiline] being set to true. +func WithIndentPrefix(prefix string) Options { + return jsontext.WithIndentPrefix(prefix) +} + +// AppendQuote appends a double-quoted JSON string literal representing src +// to dst and returns the extended buffer. +// It uses the minimal string representation per RFC 8785, section 3.2.2.2. +// Invalid UTF-8 bytes are replaced with the Unicode replacement character +// and an error is returned at the end indicating the presence of invalid UTF-8. +// The dst must not overlap with the src. +func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) { + return jsontext.AppendQuote[Bytes](dst, src) +} + +// AppendUnquote appends the decoded interpretation of src as a +// double-quoted JSON string literal to dst and returns the extended buffer. +// The input src must be a JSON string without any surrounding whitespace. +// Invalid UTF-8 bytes are replaced with the Unicode replacement character +// and an error is returned at the end indicating the presence of invalid UTF-8. +// Any trailing bytes after the JSON string literal results in an error. +// The dst must not overlap with the src. +func AppendUnquote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) { + return jsontext.AppendUnquote[Bytes](dst, src) +} + +// ErrDuplicateName indicates that a JSON token could not be +// encoded or decoded because it results in a duplicate JSON object name. +// This error is directly wrapped within a [SyntacticError] when produced. +// +// The name of a duplicate JSON object member can be extracted as: +// +// err := ... +// var serr jsontext.SyntacticError +// if errors.As(err, &serr) && serr.Err == jsontext.ErrDuplicateName { +// ptr := serr.JSONPointer // JSON pointer to duplicate name +// name := ptr.LastToken() // duplicate name itself +// ... +// } +// +// This error is only returned if [AllowDuplicateNames] is false. +var ErrDuplicateName = jsontext.ErrDuplicateName + +// ErrNonStringName indicates that a JSON token could not be +// encoded or decoded because it is not a string, +// as required for JSON object names according to RFC 8259, section 4. +// This error is directly wrapped within a [SyntacticError] when produced. +var ErrNonStringName = jsontext.ErrNonStringName + +// Pointer is a JSON Pointer (RFC 6901) that references a particular JSON value +// relative to the root of the top-level JSON value. +// +// A Pointer is a slash-separated list of tokens, where each token is +// either a JSON object name or an index to a JSON array element +// encoded as a base-10 integer value. +// It is impossible to distinguish between an array index and an object name +// (that happens to be an base-10 encoded integer) without also knowing +// the structure of the top-level JSON value that the pointer refers to. +// +// There is exactly one representation of a pointer to a particular value, +// so comparability of Pointer values is equivalent to checking whether +// they both point to the exact same value. +type Pointer = jsontext.Pointer + +// Token represents a lexical JSON token, which may be one of the following: +// - a JSON literal (i.e., null, true, or false) +// - a JSON string (e.g., "hello, world!") +// - a JSON number (e.g., 123.456) +// - a begin or end delimiter for a JSON object (i.e., { or } ) +// - a begin or end delimiter for a JSON array (i.e., [ or ] ) +// +// A Token cannot represent entire array or object values, while a [Value] can. +// There is no Token to represent commas and colons since +// these structural tokens can be inferred from the surrounding context. +type Token = jsontext.Token + +var ( + Null = jsontext.Null + False = jsontext.False + True = jsontext.True + BeginObject = jsontext.BeginObject + EndObject = jsontext.EndObject + BeginArray = jsontext.BeginArray + EndArray = jsontext.EndArray +) + +// Bool constructs a Token representing a JSON boolean. +func Bool(b bool) Token { + return jsontext.Bool(b) +} + +// String constructs a Token representing a JSON string. +// The provided string should contain valid UTF-8, otherwise invalid characters +// may be mangled as the Unicode replacement character. +func String(s string) Token { + return jsontext.String(s) +} + +// Float constructs a Token representing a JSON number. +// The values NaN, +Inf, and -Inf will be represented +// as a JSON string with the values "NaN", "Infinity", and "-Infinity". +func Float(n float64) Token { + return jsontext.Float(n) +} + +// Int constructs a Token representing a JSON number from an int64. +func Int(n int64) Token { + return jsontext.Int(n) +} + +// Uint constructs a Token representing a JSON number from a uint64. +func Uint(n uint64) Token { + return jsontext.Uint(n) +} + +// Kind represents each possible JSON token kind with a single byte, +// which is conveniently the first byte of that kind's grammar +// with the restriction that numbers always be represented with '0': +// +// - 'n': null +// - 'f': false +// - 't': true +// - '"': string +// - '0': number +// - '{': object begin +// - '}': object end +// - '[': array begin +// - ']': array end +// +// An invalid kind is usually represented using 0, +// but may be non-zero due to invalid JSON data. +type Kind = jsontext.Kind + +// AppendFormat formats the JSON value in src and appends it to dst +// according to the specified options. +// See [Value.Format] for more details about the formatting behavior. +// +// The dst and src may overlap. +// If an error is reported, then the entirety of src is appended to dst. +func AppendFormat(dst, src []byte, opts ...Options) ([]byte, error) { + return jsontext.AppendFormat(dst, src, opts...) +} + +// Value represents a single raw JSON value, which may be one of the following: +// - a JSON literal (i.e., null, true, or false) +// - a JSON string (e.g., "hello, world!") +// - a JSON number (e.g., 123.456) +// - an entire JSON object (e.g., {"fizz":"buzz"} ) +// - an entire JSON array (e.g., [1,2,3] ) +// +// Value can represent entire array or object values, while [Token] cannot. +// Value may contain leading and/or trailing whitespace. +type Value = jsontext.Value diff --git a/vendor/github.com/go-json-experiment/json/jsontext/decode.go b/vendor/github.com/go-json-experiment/json/jsontext/decode.go index 49a75f23c27..9326acefcb2 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/decode.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/decode.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( @@ -136,14 +138,32 @@ func (d *Decoder) Reset(r io.Reader, opts ...Options) { case d.s.Flags.Get(jsonflags.WithinArshalCall): panic("jsontext: cannot reset Decoder passed to json.UnmarshalerFrom") } - d.s.reset(nil, r, opts...) + // Reuse the buffer if it does not alias a previous [bytes.Buffer]. + b := d.s.buf[:0] + if _, ok := d.s.rd.(*bytes.Buffer); ok { + b = nil + } + d.s.reset(b, r, opts...) } func (d *decoderState) reset(b []byte, r io.Reader, opts ...Options) { d.state.reset() d.decodeBuffer = decodeBuffer{buf: b, rd: r} - d.Struct = jsonopts.Struct{} - d.Struct.Join(opts...) + opts2 := jsonopts.Struct{} // avoid mutating d.Struct in case it is part of opts + opts2.Join(opts...) + d.Struct = opts2 +} + +// Options returns the options used to construct the encoder and +// may additionally contain semantic options passed to a +// [encoding/json/v2.UnmarshalDecode] call. +// +// If operating within +// a [encoding/json/v2.UnmarshalerFrom.UnmarshalJSONFrom] method call or +// a [encoding/json/v2.UnmarshalFromFunc] function call, +// then the returned options are only valid within the call. +func (d *Decoder) Options() Options { + return &d.s.Struct } var errBufferWriteAfterNext = errors.New("invalid bytes.Buffer.Write call after calling bytes.Buffer.Next") @@ -603,7 +623,7 @@ func (d *decoderState) ReadToken() (Token, error) { } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ObjectStart, nil + return BeginObject, nil case '}': if err = d.Tokens.popObject(); err != nil { @@ -615,7 +635,7 @@ func (d *decoderState) ReadToken() (Token, error) { } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ObjectEnd, nil + return EndObject, nil case '[': if err = d.Tokens.pushArray(); err != nil { @@ -623,7 +643,7 @@ func (d *decoderState) ReadToken() (Token, error) { } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ArrayStart, nil + return BeginArray, nil case ']': if err = d.Tokens.popArray(); err != nil { @@ -631,7 +651,7 @@ func (d *decoderState) ReadToken() (Token, error) { } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ArrayEnd, nil + return EndArray, nil default: err = jsonwire.NewInvalidCharacterError(d.buf[pos:], "at start of value") @@ -754,7 +774,8 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) { // CheckNextValue checks whether the next value is syntactically valid, // but does not advance the read offset. -func (d *decoderState) CheckNextValue() error { +// If last, it verifies that the stream cleanly terminates with [io.EOF]. +func (d *decoderState) CheckNextValue(last bool) error { d.PeekKind() // populates d.peekPos and d.peekErr pos, err := d.peekPos, d.peekErr d.peekPos, d.peekErr = 0, nil @@ -765,13 +786,18 @@ func (d *decoderState) CheckNextValue() error { var flags jsonwire.ValueFlags if pos, err := d.consumeValue(&flags, pos, d.Tokens.Depth()); err != nil { return wrapSyntacticError(d, err, pos, +1) + } else if last { + return d.checkEOF(pos) } return nil } // CheckEOF verifies that the input has no more data. func (d *decoderState) CheckEOF() error { - switch pos, err := d.consumeWhitespace(d.prevEnd); err { + return d.checkEOF(d.prevEnd) +} +func (d *decoderState) checkEOF(pos int) error { + switch pos, err := d.consumeWhitespace(pos); err { case nil: err := jsonwire.NewInvalidCharacterError(d.buf[pos:], "after top-level value") return wrapSyntacticError(d, err, pos, 0) @@ -1110,8 +1136,8 @@ func (d *Decoder) UnreadBuffer() []byte { // StackDepth returns the depth of the state machine for read JSON data. // Each level on the stack represents a nested JSON object or array. -// It is incremented whenever an [ObjectStart] or [ArrayStart] token is encountered -// and decremented whenever an [ObjectEnd] or [ArrayEnd] token is encountered. +// It is incremented whenever an [BeginObject] or [BeginArray] token is encountered +// and decremented whenever an [EndObject] or [EndArray] token is encountered. // The depth is zero-indexed, where zero represents the top-level JSON value. func (d *Decoder) StackDepth() int { // NOTE: Keep in sync with Encoder.StackDepth. diff --git a/vendor/github.com/go-json-experiment/json/jsontext/doc.go b/vendor/github.com/go-json-experiment/json/jsontext/doc.go index f212e56a78c..22081df0537 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/doc.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/doc.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + // Package jsontext implements syntactic processing of JSON // as specified in RFC 4627, RFC 7159, RFC 7493, RFC 8259, and RFC 8785. // JSON is a simple data interchange format that can represent @@ -18,8 +20,8 @@ // - a JSON literal (i.e., null, true, or false) // - a JSON string (e.g., "hello, world!") // - a JSON number (e.g., 123.456) -// - a start or end delimiter for a JSON object (i.e., '{' or '}') -// - a start or end delimiter for a JSON array (i.e., '[' or ']') +// - a begin or end delimiter for a JSON object (i.e., '{' or '}') +// - a begin or end delimiter for a JSON array (i.e., '[' or ']') // // A JSON token is represented by the [Token] type in Go. Technically, // there are two additional structural characters (i.e., ':' and ','), @@ -96,6 +98,10 @@ // RFC 7493 is a stricter subset of RFC 8259 and fully compliant with it. // In particular, it makes specific choices about behavior that RFC 8259 // leaves as undefined in order to ensure greater interoperability. +// +// # Security Considerations +// +// See the "Security Considerations" section in [encoding/json/v2]. package jsontext // requireKeyedLiterals can be embedded in a struct to require keyed literals. diff --git a/vendor/github.com/go-json-experiment/json/jsontext/encode.go b/vendor/github.com/go-json-experiment/json/jsontext/encode.go index 58fc060b20d..110820306ad 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/encode.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/encode.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( @@ -25,19 +27,19 @@ import ( // // can be composed with the following calls (ignoring errors for brevity): // -// e.WriteToken(ObjectStart) // { +// e.WriteToken(BeginObject) // { // e.WriteToken(String("name")) // "name" // e.WriteToken(String("value")) // "value" // e.WriteValue(Value(`"array"`)) // "array" -// e.WriteToken(ArrayStart) // [ +// e.WriteToken(BeginArray) // [ // e.WriteToken(Null) // null // e.WriteToken(False) // false // e.WriteValue(Value("true")) // true // e.WriteToken(Float(3.14159)) // 3.14159 -// e.WriteToken(ArrayEnd) // ] +// e.WriteToken(EndArray) // ] // e.WriteValue(Value(`"object"`)) // "object" // e.WriteValue(Value(`{"k":"v"}`)) // {"k":"v"} -// e.WriteToken(ObjectEnd) // } +// e.WriteToken(EndObject) // } // // The above is one of many possible sequence of calls and // may not represent the most sensible method to call for any given token/value. @@ -72,8 +74,8 @@ type encodeBuffer struct { // maxValue is the approximate maximum Value size passed to WriteValue. maxValue int - // unusedCache is the buffer returned by the UnusedBuffer method. - unusedCache []byte + // availBuffer is the buffer returned by the AvailableBuffer method. + availBuffer []byte // always has zero length // bufStats is statistics about buffer utilization. // It is only used with pooled encoders in pools.go. bufStats bufferStatistics @@ -105,17 +107,23 @@ func (e *Encoder) Reset(w io.Writer, opts ...Options) { case e.s.Flags.Get(jsonflags.WithinArshalCall): panic("jsontext: cannot reset Encoder passed to json.MarshalerTo") } - e.s.reset(nil, w, opts...) + // Reuse the buffer if it does not alias a previous [bytes.Buffer]. + b := e.s.Buf[:0] + if _, ok := e.s.wr.(*bytes.Buffer); ok { + b = nil + } + e.s.reset(b, w, opts...) } func (e *encoderState) reset(b []byte, w io.Writer, opts ...Options) { e.state.reset() - e.encodeBuffer = encodeBuffer{Buf: b, wr: w, bufStats: e.bufStats} + e.encodeBuffer = encodeBuffer{Buf: b, wr: w, availBuffer: e.availBuffer, bufStats: e.bufStats} if bb, ok := w.(*bytes.Buffer); ok && bb != nil { - e.Buf = bb.Bytes()[bb.Len():] // alias the unused buffer of bb + e.Buf = bb.AvailableBuffer() // alias the unused buffer of bb } - e.Struct = jsonopts.Struct{} - e.Struct.Join(opts...) + opts2 := jsonopts.Struct{} // avoid mutating e.Struct in case it is part of opts + opts2.Join(opts...) + e.Struct = opts2 if e.Flags.Get(jsonflags.Multiline) { if !e.Flags.Has(jsonflags.SpaceAfterColon) { e.Flags.Set(jsonflags.SpaceAfterColon | 1) @@ -130,6 +138,18 @@ func (e *encoderState) reset(b []byte, w io.Writer, opts ...Options) { } } +// Options returns the options used to construct the decoder and +// may additionally contain semantic options passed to a +// [encoding/json/v2.MarshalEncode] call. +// +// If operating within +// a [encoding/json/v2.MarshalerTo.MarshalJSONTo] method call or +// a [encoding/json/v2.MarshalToFunc] function call, +// then the returned options are only valid within the call. +func (e *Encoder) Options() Options { + return &e.s.Struct +} + // NeedFlush determines whether to flush at this point. func (e *encoderState) NeedFlush() bool { // NOTE: This function is carefully written to be inlinable. @@ -218,7 +238,7 @@ func (e *encodeBuffer) unflushedBuffer() []byte { return e.Buf } func (e *encoderState) avoidFlush() bool { switch { case e.Tokens.Last.Length() == 0: - // Never flush after ObjectStart or ArrayStart since we don't know yet + // Never flush after BeginObject or BeginArray since we don't know yet // if the object or array will end up being empty. return true case e.Tokens.Last.needObjectValue(): @@ -450,9 +470,9 @@ func (e *encoderState) AppendRaw(k Kind, safeASCII bool, appendFn func([]byte) ( isVerbatim := safeASCII || !jsonwire.NeedEscape(b[pos+len(`"`):len(b)-len(`"`)]) if !isVerbatim { var err error - b2 := append(e.unusedCache, b[pos+len(`"`):len(b)-len(`"`)]...) + b2 := append(e.availBuffer, b[pos+len(`"`):len(b)-len(`"`)]...) b, err = jsonwire.AppendQuote(b[:pos], string(b2), &e.Flags) - e.unusedCache = b2[:0] + e.availBuffer = b2[:0] if err != nil { return wrapSyntacticError(e, err, pos, +1) } @@ -698,7 +718,7 @@ func (e *encoderState) reformatValue(dst []byte, src Value, depth int) ([]byte, // appends it to the end of src, reformatting whitespace and strings as needed. // It returns the extended dst buffer and the number of consumed input bytes. func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, int, error) { - // Append object start. + // Append object begin. if len(src) == 0 || src[0] != '{' { panic("BUG: reformatObject must be called with a buffer that starts with '{'") } else if depth == maxNestingDepth+1 { @@ -809,7 +829,7 @@ func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, // appends it to the end of dst, reformatting whitespace and strings as needed. // It returns the extended dst buffer and the number of consumed input bytes. func (e *encoderState) reformatArray(dst []byte, src Value, depth int) ([]byte, int, error) { - // Append array start. + // Append array begin. if len(src) == 0 || src[0] != '[' { panic("BUG: reformatArray must be called with a buffer that starts with '['") } else if depth == maxNestingDepth+1 { @@ -885,20 +905,20 @@ func (e *Encoder) OutputOffset() int64 { return e.s.previousOffsetEnd() } -// UnusedBuffer returns a zero-length buffer with a possible non-zero capacity. +// AvailableBuffer returns a zero-length buffer with a possible non-zero capacity. // This buffer is intended to be used to populate a [Value] // being passed to an immediately succeeding [Encoder.WriteValue] call. // // Example usage: // -// b := d.UnusedBuffer() +// b := d.AvailableBuffer() // b = append(b, '"') // b = appendString(b, v) // append the string formatting of v // b = append(b, '"') // ... := d.WriteValue(b) // // It is the user's responsibility to ensure that the value is valid JSON. -func (e *Encoder) UnusedBuffer() []byte { +func (e *Encoder) AvailableBuffer() []byte { // NOTE: We don't return e.buf[len(e.buf):cap(e.buf)] since WriteValue would // need to take special care to avoid mangling the data while reformatting. // WriteValue can't easily identify whether the input Value aliases e.buf @@ -906,16 +926,16 @@ func (e *Encoder) UnusedBuffer() []byte { // Should this ever alias e.buf, we need to consider how it operates with // the specialized performance optimization for bytes.Buffer. n := 1 << bits.Len(uint(e.s.maxValue|63)) // fast approximation for max length - if cap(e.s.unusedCache) < n { - e.s.unusedCache = make([]byte, 0, n) + if cap(e.s.availBuffer) < n { + e.s.availBuffer = make([]byte, 0, n) } - return e.s.unusedCache + return e.s.availBuffer } // StackDepth returns the depth of the state machine for written JSON data. // Each level on the stack represents a nested JSON object or array. -// It is incremented whenever an [ObjectStart] or [ArrayStart] token is encountered -// and decremented whenever an [ObjectEnd] or [ArrayEnd] token is encountered. +// It is incremented whenever an [BeginObject] or [BeginArray] token is encountered +// and decremented whenever an [EndObject] or [EndArray] token is encountered. // The depth is zero-indexed, where zero represents the top-level JSON value. func (e *Encoder) StackDepth() int { // NOTE: Keep in sync with Decoder.StackDepth. diff --git a/vendor/github.com/go-json-experiment/json/jsontext/errors.go b/vendor/github.com/go-json-experiment/json/jsontext/errors.go index eb5f0e259ff..5ce906fdd97 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/errors.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/errors.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( diff --git a/vendor/github.com/go-json-experiment/json/jsontext/export.go b/vendor/github.com/go-json-experiment/json/jsontext/export.go index ab600b5e26e..866954b6172 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/export.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/export.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( diff --git a/vendor/github.com/go-json-experiment/json/jsontext/options.go b/vendor/github.com/go-json-experiment/json/jsontext/options.go index 8696e02736d..56819024b70 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/options.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/options.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( @@ -269,6 +271,7 @@ func WithIndentPrefix(prefix string) Options { /* // TODO(https://go.dev/issue/56733): Implement WithByteLimit and WithDepthLimit. +// Remember to also update the "Security Considerations" section. // WithByteLimit sets a limit on the number of bytes of input or output bytes // that may be consumed or produced for each top-level JSON value. diff --git a/vendor/github.com/go-json-experiment/json/jsontext/pools.go b/vendor/github.com/go-json-experiment/json/jsontext/pools.go index 63941baacb4..cf59d99b924 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/pools.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/pools.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( diff --git a/vendor/github.com/go-json-experiment/json/jsontext/quote.go b/vendor/github.com/go-json-experiment/json/jsontext/quote.go index 8faa4352b15..8d475b816b0 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/quote.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/quote.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( diff --git a/vendor/github.com/go-json-experiment/json/jsontext/state.go b/vendor/github.com/go-json-experiment/json/jsontext/state.go index 6c373b087e7..2da28c1a690 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/state.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/state.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( @@ -15,30 +17,30 @@ import ( "github.com/go-json-experiment/json/internal/jsonwire" ) -var ( - // ErrDuplicateName indicates that a JSON token could not be - // encoded or decoded because it results in a duplicate JSON object name. - // This error is directly wrapped within a [SyntacticError] when produced. - // - // The name of a duplicate JSON object member can be extracted as: - // - // err := ... - // var serr jsontext.SyntacticError - // if errors.As(err, &serr) && serr.Err == jsontext.ErrDuplicateName { - // ptr := serr.JSONPointer // JSON pointer to duplicate name - // name := ptr.LastToken() // duplicate name itself - // ... - // } - // - // This error is only returned if [AllowDuplicateNames] is false. - ErrDuplicateName = errors.New("duplicate object member name") - - // ErrNonStringName indicates that a JSON token could not be - // encoded or decoded because it is not a string, - // as required for JSON object names according to RFC 8259, section 4. - // This error is directly wrapped within a [SyntacticError] when produced. - ErrNonStringName = errors.New("object member name must be a string") +// ErrDuplicateName indicates that a JSON token could not be +// encoded or decoded because it results in a duplicate JSON object name. +// This error is directly wrapped within a [SyntacticError] when produced. +// +// The name of a duplicate JSON object member can be extracted as: +// +// err := ... +// var serr jsontext.SyntacticError +// if errors.As(err, &serr) && serr.Err == jsontext.ErrDuplicateName { +// ptr := serr.JSONPointer // JSON pointer to duplicate name +// name := ptr.LastToken() // duplicate name itself +// ... +// } +// +// This error is only returned if [AllowDuplicateNames] is false. +var ErrDuplicateName = errors.New("duplicate object member name") + +// ErrNonStringName indicates that a JSON token could not be +// encoded or decoded because it is not a string, +// as required for JSON object names according to RFC 8259, section 4. +// This error is directly wrapped within a [SyntacticError] when produced. +var ErrNonStringName = errors.New("object member name must be a string") +var ( errMissingValue = errors.New("missing value after object name") errMismatchDelim = errors.New("mismatching structural token for object or array") errMaxDepth = errors.New("exceeded max depth") @@ -295,7 +297,7 @@ func (m *stateMachine) appendNumber() error { return m.appendLiteral() } -// pushObject appends a JSON start object token as next in the sequence. +// pushObject appends a JSON begin object token as next in the sequence. // If an error is returned, the state is not mutated. func (m *stateMachine) pushObject() error { switch { @@ -330,7 +332,7 @@ func (m *stateMachine) popObject() error { } } -// pushArray appends a JSON start array token as next in the sequence. +// pushArray appends a JSON begin array token as next in the sequence. // If an error is returned, the state is not mutated. func (m *stateMachine) pushArray() error { switch { diff --git a/vendor/github.com/go-json-experiment/json/jsontext/token.go b/vendor/github.com/go-json-experiment/json/jsontext/token.go index b389fc00942..23911dfd78c 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/token.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/token.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( @@ -31,8 +33,8 @@ var errInvalidToken = errors.New("invalid jsontext.Token") // - a JSON literal (i.e., null, true, or false) // - a JSON string (e.g., "hello, world!") // - a JSON number (e.g., 123.456) -// - a start or end delimiter for a JSON object (i.e., { or } ) -// - a start or end delimiter for a JSON array (i.e., [ or ] ) +// - a begin or end delimiter for a JSON object (i.e., { or } ) +// - a begin or end delimiter for a JSON array (i.e., [ or ] ) // // A Token cannot represent entire array or object values, while a [Value] can. // There is no Token to represent commas and colons since @@ -94,10 +96,10 @@ var ( False Token = rawToken("false") True Token = rawToken("true") - ObjectStart Token = rawToken("{") - ObjectEnd Token = rawToken("}") - ArrayStart Token = rawToken("[") - ArrayEnd Token = rawToken("]") + BeginObject Token = rawToken("{") + EndObject Token = rawToken("}") + BeginArray Token = rawToken("[") + EndArray Token = rawToken("]") zeroString Token = rawToken(`""`) zeroNumber Token = rawToken(`0`) @@ -176,14 +178,14 @@ func (t Token) Clone() Token { return False case True.raw: return True - case ObjectStart.raw: - return ObjectStart - case ObjectEnd.raw: - return ObjectEnd - case ArrayStart.raw: - return ArrayStart - case ArrayEnd.raw: - return ArrayEnd + case BeginObject.raw: + return BeginObject + case EndObject.raw: + return EndObject + case BeginArray.raw: + return BeginArray + case EndArray.raw: + return EndArray } } @@ -479,9 +481,9 @@ func (t Token) Kind() Kind { // - 't': true // - '"': string // - '0': number -// - '{': object start +// - '{': object begin // - '}': object end -// - '[': array start +// - '[': array begin // - ']': array end // // An invalid kind is usually represented using 0, diff --git a/vendor/github.com/go-json-experiment/json/jsontext/value.go b/vendor/github.com/go-json-experiment/json/jsontext/value.go index f2fd14ba56a..baaaddade4e 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/value.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/value.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package jsontext import ( diff --git a/vendor/github.com/go-json-experiment/json/migrate.sh b/vendor/github.com/go-json-experiment/json/migrate.sh index 8d9a02038fa..9c34f26eb94 100644 --- a/vendor/github.com/go-json-experiment/json/migrate.sh +++ b/vendor/github.com/go-json-experiment/json/migrate.sh @@ -3,229 +3,46 @@ GOROOT=${1:-../go} JSONROOT="." -# Check if the Go toolchain has a clean checkout. -if [ -n "$(cd $GOROOT; git status --porcelain)" ]; then - (cd $GOROOT; git status --porcelain) - echo "Working directory is not clean." - echo "" - echo "To cleanup, run:" - echo " (cd $GOROOT && git checkout . && git clean -fd)" - exit 1 -fi - -/bin/rm -rf $GOROOT/src/encoding/json/* -cp $JSONROOT/v1/* $GOROOT/src/encoding/json/ -cp -r $JSONROOT/internal/ $GOROOT/src/encoding/json/internal/ -mkdir $GOROOT/src/encoding/json/v2/ -cp -r $JSONROOT/*.go $GOROOT/src/encoding/json/v2/ -mkdir $GOROOT/src/encoding/json/jsontext/ -cp -r $JSONROOT/jsontext/*.go $GOROOT/src/encoding/json/jsontext/ -find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json/v1|encoding/json|g' {} + -find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json/|encoding/json/|g' {} + -find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json|encoding/json/v2|g' {} + - -# Adjust for changed package path. -sed -i 's/json\.struct/v2.struct/g' $GOROOT/src/encoding/json/v2/errors_test.go - -# Add "encoding/json/v2" to list of packages to ignore structtag findings. -sed -i 's|"encoding/json"|"encoding/json", "encoding/json/v2"|g' $GOROOT/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go - -# Adjust tests that hardcode formatted error strings. -sed -i 's/}`, "Time.UnmarshalJSON: input is not a JSON string/}`, "json: cannot unmarshal JSON object into Go type time.Time/g' $GOROOT/src/time/time_test.go -sed -i 's/]`, "Time.UnmarshalJSON: input is not a JSON string/]`, "json: cannot unmarshal JSON array into Go type time.Time/g' $GOROOT/src/time/time_test.go - -# Adjust for changed dependency tree. -sed -i 's|encoding/json|encoding/json/v2|g' $GOROOT/src/cmd/go/internal/imports/scan_test.go -sed -i 's|encoding/binary|internal/reflectlite|g' $GOROOT/src/cmd/go/internal/imports/scan_test.go -LINE=$(sed -n '/encoding\/json, encoding\/pem, encoding\/xml, mime;/=' $GOROOT/src/go/build/deps_test.go) -sed -i 's|encoding/json, encoding/pem, encoding/xml, mime|encoding/pem, encoding/xml, mime|g' $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 1)) i\\\\" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 2)) i\\\tSTR, errors" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 3)) i\\\t< encoding/json/internal" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 4)) i\\\t< encoding/json/internal/jsonflags" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 5)) i\\\t< encoding/json/internal/jsonopts" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 6)) i\\\t< encoding/json/internal/jsonwire" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 7)) i\\\t< encoding/json/jsontext;" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 8)) i\\\\" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+ 9)) i\\\tFMT," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+10)) i\\\tencoding/hex," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+11)) i\\\tencoding/base32," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+12)) i\\\tencoding/base64," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+13)) i\\\tencoding/binary," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+14)) i\\\tencoding/json/jsontext," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+15)) i\\\tencoding/json/internal," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+16)) i\\\tencoding/json/internal/jsonflags," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+17)) i\\\tencoding/json/internal/jsonopts," $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+18)) i\\\tencoding/json/internal/jsonwire" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+19)) i\\\t< encoding/json/v2" $GOROOT/src/go/build/deps_test.go -sed -i "$((LINE+20)) i\\\t< encoding/json;" $GOROOT/src/go/build/deps_test.go -LINE=$(sed -n '/Test-only packages can have anything they want/=' $GOROOT/src/go/build/deps_test.go) -sed -i "$((LINE+1)) i\\\tFMT, compress/gzip, embed, encoding/binary < encoding/json/internal/jsontest;" $GOROOT/src/go/build/deps_test.go - -# Adjust for newly added API. -ISSUE=63397 # TODO: Replace with formal proposal issue for encoding/json/v2 -FILE=$(cd $GOROOT/api; ls -v | tail -n 1) -echo "pkg encoding/json, func CallMethodsWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func DefaultOptionsV1() jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func EscapeInvalidUTF8(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func FormatBytesWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func FormatTimeWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func MatchCaseSensitiveDelimiter(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func MergeWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func OmitEmptyWithLegacyDefinition(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func ReportErrorsWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func StringifyWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, func UnmarshalArrayFromAnyLength(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, method (*Number) UnmarshalJSONFrom(*jsontext.Decoder, jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, method (*UnmarshalTypeError) Unwrap() error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, method (Number) MarshalJSONTo(*jsontext.Encoder, jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, type Marshaler = json.Marshaler #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, type Options = jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, type RawMessage = jsontext.Value #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, type UnmarshalTypeError struct, Err error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json, type Unmarshaler = json.Unmarshaler #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func AllowDuplicateNames(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func AllowInvalidUTF8(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func AppendFormat([]uint8, []uint8, ...jsonopts.Options) ([]uint8, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func AppendQuote[\$0 interface{ ~[]uint8 | ~string }]([]uint8, \$0) ([]uint8, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func AppendUnquote[\$0 interface{ ~[]uint8 | ~string }]([]uint8, \$0) ([]uint8, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func Bool(bool) Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func CanonicalizeRawFloats(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func CanonicalizeRawInts(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func EscapeForHTML(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func EscapeForJS(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func Float(float64) Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func Int(int64) Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func Multiline(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func NewDecoder(io.Reader, ...jsonopts.Options) *Decoder #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func NewEncoder(io.Writer, ...jsonopts.Options) *Encoder #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func PreserveRawStrings(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func ReorderRawObjects(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func SpaceAfterColon(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func SpaceAfterComma(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func String(string) Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func Uint(uint64) Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func WithIndent(string) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, func WithIndentPrefix(string) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) InputOffset() int64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) PeekKind() Kind #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) ReadToken() (Token, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) ReadValue() (Value, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) Reset(io.Reader, ...jsonopts.Options) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) SkipValue() error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) StackDepth() int #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) StackIndex(int) (Kind, int64) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) StackPointer() Pointer #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Decoder) UnreadBuffer() []uint8 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) OutputOffset() int64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) Reset(io.Writer, ...jsonopts.Options) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) StackDepth() int #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) StackIndex(int) (Kind, int64) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) StackPointer() Pointer #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) UnusedBuffer() []uint8 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) WriteToken(Token) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Encoder) WriteValue(Value) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*SyntacticError) Error() string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*SyntacticError) Unwrap() error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Value) Canonicalize(...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Value) Compact(...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Value) Format(...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Value) Indent(...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (*Value) UnmarshalJSON([]uint8) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Kind) String() string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Pointer) AppendToken(string) Pointer #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Pointer) Contains(Pointer) bool #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Pointer) LastToken() string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Pointer) Parent() Pointer #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Pointer) Tokens() iter.Seq[string] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) Bool() bool #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) Clone() Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) Float() float64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) Int() int64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) Kind() Kind #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) String() string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Token) Uint() uint64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Value) Clone() Value #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Value) IsValid(...jsonopts.Options) bool #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Value) Kind() Kind #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Value) MarshalJSON() ([]uint8, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, method (Value) String() string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Decoder struct #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Encoder struct #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Kind uint8 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Options = jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Pointer string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type SyntacticError struct #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type SyntacticError struct, ByteOffset int64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type SyntacticError struct, Err error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type SyntacticError struct, JSONPointer Pointer #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Token struct #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, type Value []uint8 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var ArrayEnd Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var ArrayStart Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var ErrDuplicateName error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var ErrNonStringName error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var False Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var Internal exporter #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var Null Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var ObjectEnd Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var ObjectStart Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/jsontext, var True Token #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func DefaultOptionsV2() jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func Deterministic(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func DiscardUnknownMembers(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func FormatNilMapAsNull(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func FormatNilSliceAsNull(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func GetOption[\$0 interface{}](jsonopts.Options, func(\$0) jsonopts.Options) (\$0, bool) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func JoinMarshalers(...*typedArshalers[jsontext.Encoder]) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func JoinOptions(...jsonopts.Options) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func JoinUnmarshalers(...*typedArshalers[jsontext.Decoder]) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func Marshal(interface{}, ...jsonopts.Options) ([]uint8, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func MarshalEncode(*jsontext.Encoder, interface{}, ...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func MarshalFunc[\$0 interface{}](func(\$0) ([]uint8, error)) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func MarshalToFunc[\$0 interface{}](func(*jsontext.Encoder, \$0, jsonopts.Options) error) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func MarshalWrite(io.Writer, interface{}, ...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func MatchCaseInsensitiveNames(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func OmitZeroStructFields(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func RejectUnknownMembers(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func StringifyNumbers(bool) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func Unmarshal([]uint8, interface{}, ...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func UnmarshalDecode(*jsontext.Decoder, interface{}, ...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func UnmarshalFromFunc[\$0 interface{}](func(*jsontext.Decoder, \$0, jsonopts.Options) error) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func UnmarshalFunc[\$0 interface{}](func([]uint8, \$0) error) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func UnmarshalRead(io.Reader, interface{}, ...jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func WithMarshalers(*typedArshalers[jsontext.Encoder]) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, func WithUnmarshalers(*typedArshalers[jsontext.Decoder]) jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, method (*SemanticError) Error() string #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, method (*SemanticError) Unwrap() error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Marshaler interface { MarshalJSON } #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Marshaler interface, MarshalJSON() ([]uint8, error) #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type MarshalerTo interface { MarshalJSONTo } #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type MarshalerTo interface, MarshalJSONTo(*jsontext.Encoder, jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Marshalers = typedArshalers[jsontext.Encoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Options = jsonopts.Options #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct, ByteOffset int64 #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct, Err error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct, GoType reflect.Type #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct, JSONKind jsontext.Kind #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct, JSONPointer jsontext.Pointer #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type SemanticError struct, JSONValue jsontext.Value #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Unmarshaler interface { UnmarshalJSON } #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Unmarshaler interface, UnmarshalJSON([]uint8) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type UnmarshalerFrom interface { UnmarshalJSONFrom } #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type UnmarshalerFrom interface, UnmarshalJSONFrom(*jsontext.Decoder, jsonopts.Options) error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, type Unmarshalers = typedArshalers[jsontext.Decoder] #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, var ErrUnknownName error #$ISSUE" >> $GOROOT/api/$FILE -echo "pkg encoding/json/v2, var SkipFunc error #$ISSUE" >> $GOROOT/api/$FILE -# The following declarations were moved to encoding/json/v2 or encoding/json/jsontext. -echo "pkg encoding/json, method (*RawMessage) UnmarshalJSON([]uint8) error" >> $GOROOT/api/except.txt -echo "pkg encoding/json, method (RawMessage) MarshalJSON() ([]uint8, error)" >> $GOROOT/api/except.txt -echo "pkg encoding/json, type Marshaler interface { MarshalJSON }" >> $GOROOT/api/except.txt -echo "pkg encoding/json, type Marshaler interface, MarshalJSON() ([]uint8, error)" >> $GOROOT/api/except.txt -echo "pkg encoding/json, type RawMessage []uint8" >> $GOROOT/api/except.txt -echo "pkg encoding/json, type Unmarshaler interface { UnmarshalJSON }" >> $GOROOT/api/except.txt -echo "pkg encoding/json, type Unmarshaler interface, UnmarshalJSON([]uint8) error" >> $GOROOT/api/except.txt - -# Run the tests. -(cd $GOROOT/src; ./all.bash) +cp $JSONROOT/alias_gen.go $JSONROOT/alias_gen.go.bak +rm -r $JSONROOT/*.go $JSONROOT/internal $JSONROOT/jsontext $JSONROOT/v1 +mv $JSONROOT/alias_gen.go.bak $JSONROOT/alias_gen.go +cp -r $GOROOT/src/encoding/json/v2/*.go $JSONROOT/ +cp -r $GOROOT/src/encoding/json/internal/ $JSONROOT/internal/ +cp -r $GOROOT/src/encoding/json/jsontext/ $JSONROOT/jsontext/ +mkdir $JSONROOT/v1 +for X in $GOROOT/src/encoding/json/v2_*.go; do + cp $X $JSONROOT/v1/$(basename $X | sed "s/v2_//") +done +cd $JSONROOT +for X in $(git ls-files --cached --others --exclude-standard | grep ".*[.]go$"); do + if [ ! -e "$X" ]; then + continue + fi + sed -i 's/go:build goexperiment.jsonv2$/go:build !goexperiment.jsonv2 || !go1.25/' $X + sed -i 's|"encoding/json/v2"|"github.com/go-json-experiment/json"|' $X + sed -i 's|"encoding/json/internal"|"github.com/go-json-experiment/json/internal"|' $X + sed -i 's|"encoding/json/internal/jsonflags"|"github.com/go-json-experiment/json/internal/jsonflags"|' $X + sed -i 's|"encoding/json/internal/jsonopts"|"github.com/go-json-experiment/json/internal/jsonopts"|' $X + sed -i 's|"encoding/json/internal/jsontest"|"github.com/go-json-experiment/json/internal/jsontest"|' $X + sed -i 's|"encoding/json/internal/jsonwire"|"github.com/go-json-experiment/json/internal/jsonwire"|' $X + sed -i 's|"encoding/json/jsontext"|"github.com/go-json-experiment/json/jsontext"|' $X + sed -i 's|"encoding/json"|"github.com/go-json-experiment/json/v1"|' $X + sed -i 's|"internal/zstd"|"github.com/go-json-experiment/json/internal/zstd"|' $X + goimports -w $X +done +sed -i 's/v2[.]struct/json.struct/' $JSONROOT/errors_test.go +sed -i 's|jsonv1 "github.com/go-json-experiment/json/v1"|jsonv1 "encoding/json"|' $JSONROOT/bench_test.go + +# TODO(go1.25): Remove test that relies on "synctest" that is not available yet. +sed -i '/Issue #73733/,+17d' $JSONROOT/v1/encode_test.go +goimports -w $JSONROOT/v1/encode_test.go + +# Remove documentation that only makes sense within the stdlib. +sed -i '/This package .* is experimental/,+4d' $JSONROOT/doc.go +sed -i '/This package .* is experimental/,+4d' $JSONROOT/jsontext/doc.go + +git checkout internal/zstd # we still need local copy of zstd for testing + +go run alias_gen.go "encoding/json" $JSONROOT/v1 +go run alias_gen.go "encoding/json/v2" $JSONROOT +go run alias_gen.go "encoding/json/jsontext" $JSONROOT/jsontext diff --git a/vendor/github.com/go-json-experiment/json/options.go b/vendor/github.com/go-json-experiment/json/options.go index 787b96d2bb5..96758cbea6b 100644 --- a/vendor/github.com/go-json-experiment/json/options.go +++ b/vendor/github.com/go-json-experiment/json/options.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.jsonv2 || !go1.25 + package json import ( @@ -75,9 +77,7 @@ type Options = jsonopts.Options // Properties set in later options override the value of previously set properties. func JoinOptions(srcs ...Options) Options { var dst jsonopts.Struct - for _, src := range srcs { - dst.Join(src) - } + dst.Join(srcs...) return &dst } @@ -257,7 +257,7 @@ func (*unmarshalersOption) JSONOptions(internal.NotForPublicUse) {} // Inject support into "jsonopts" to handle these types. func init() { - jsonopts.GetUnknownOption = func(src *jsonopts.Struct, zero jsonopts.Options) (any, bool) { + jsonopts.GetUnknownOption = func(src jsonopts.Struct, zero jsonopts.Options) (any, bool) { switch zero.(type) { case *marshalersOption: if !src.Flags.Has(jsonflags.Marshalers) { @@ -273,7 +273,7 @@ func init() { panic(fmt.Sprintf("unknown option %T", zero)) } } - jsonopts.JoinUnknownOption = func(dst *jsonopts.Struct, src jsonopts.Options) { + jsonopts.JoinUnknownOption = func(dst jsonopts.Struct, src jsonopts.Options) jsonopts.Struct { switch src := src.(type) { case *marshalersOption: dst.Flags.Set(jsonflags.Marshalers | 1) @@ -284,5 +284,6 @@ func init() { default: panic(fmt.Sprintf("unknown option %T", src)) } + return dst } } diff --git a/vendor/modules.txt b/vendor/modules.txt index ed5a05a1dc1..f72f384ceca 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -145,8 +145,8 @@ github.com/evanw/esbuild/pkg/api # github.com/fatih/color v1.18.0 ## explicit; go 1.17 github.com/fatih/color -# github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 -## explicit; go 1.23 +# github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 +## explicit; go 1.25 github.com/go-json-experiment/json github.com/go-json-experiment/json/internal github.com/go-json-experiment/json/internal/jsonflags