Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
v2_options.go547 linesDownload Raw Back to json
1// Copyright 2023 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5//go:build goexperiment.jsonv26 7// Migrating to v28//9// This package (i.e., [encoding/json]) is now formally known as the v1 package10// since a v2 package now exists at [encoding/json/v2].11// All the behavior of the v1 package is implemented in terms of12// the v2 package with the appropriate set of options specified that13// preserve the historical behavior of v1.14//15// The [jsonv2.Marshal] function is the newer equivalent of v1 [Marshal].16// The [jsonv2.Unmarshal] function is the newer equivalent of v1 [Unmarshal].17// The v2 functions have the same calling signature as the v1 equivalent18// except that they take in variadic [Options] arguments that can be specified19// to alter the behavior of marshal or unmarshal. Both v1 and v2 generally20// behave in similar ways, but there are some notable differences.21//22// The following is a list of differences between v1 and v2:23//24//   - In v1, JSON object members are unmarshaled into a Go struct using a25//     case-insensitive name match with the JSON name of the fields.26//     In contrast, v2 matches fields using an exact, case-sensitive match.27//     The [jsonv2.MatchCaseInsensitiveNames] and [MatchCaseSensitiveDelimiter]28//     options control this behavior difference. To explicitly specify a Go struct29//     field to use a particular name matching scheme, either the `case:ignore`30//     or the `case:strict` field option can be specified.31//     Field-specified options take precedence over caller-specified options.32//33//   - In v1, when marshaling a Go struct, a field marked as `omitempty`34//     is omitted if the field value is an "empty" Go value, which is defined as35//     false, 0, a nil pointer, a nil interface value, and36//     any empty array, slice, map, or string. In contrast, v2 redefines37//     `omitempty` to omit a field if it encodes as an "empty" JSON value,38//     which is defined as a JSON null, or an empty JSON string, object, or array.39//     The [OmitEmptyWithLegacySemantics] option controls this behavior difference.40//     Note that `omitempty` behaves identically in both v1 and v2 for a41//     Go array, slice, map, or string (assuming no user-defined MarshalJSON method42//     overrides the default representation). Existing usages of `omitempty` on a43//     Go bool, number, pointer, or interface value should migrate to specifying44//     `omitzero` instead (which is identically supported in both v1 and v2).45//46//   - In v1, a Go struct field marked as `string` can be used to quote a47//     Go string, bool, or number as a JSON string. It does not recursively48//     take effect on composite Go types. In contrast, v2 restricts49//     the `string` option to only quote a Go number as a JSON string.50//     It does recursively take effect on Go numbers within a composite Go type.51//     The [StringifyWithLegacySemantics] option controls this behavior difference.52//53//   - In v1, a nil Go slice or Go map is marshaled as a JSON null.54//     In contrast, v2 marshals a nil Go slice or Go map as55//     an empty JSON array or JSON object, respectively.56//     The [jsonv2.FormatNilSliceAsNull] and [jsonv2.FormatNilMapAsNull] options57//     control this behavior difference. To explicitly specify a Go struct field58//     to use a particular representation for nil, either the `format:emitempty`59//     or `format:emitnull` field option can be specified.60//     Field-specified options take precedence over caller-specified options.61//62//   - In v1, a Go array may be unmarshaled from a JSON array of any length.63//     In contrast, in v2 a Go array must be unmarshaled from a JSON array64//     of the same length, otherwise it results in an error.65//     The [UnmarshalArrayFromAnyLength] option controls this behavior difference.66//67//   - In v1, a Go byte array is represented as a JSON array of JSON numbers.68//     In contrast, in v2 a Go byte array is represented as a Base64-encoded JSON string.69//     The [FormatByteArrayAsArray] option controls this behavior difference.70//     To explicitly specify a Go struct field to use a particular representation,71//     either the `format:array` or `format:base64` field option can be specified.72//     Field-specified options take precedence over caller-specified options.73//74//   - In v1, MarshalJSON methods declared on a pointer receiver are only called75//     if the Go value is addressable. In contrast, in v2 a MarshalJSON method76//     is always callable regardless of addressability.77//     The [CallMethodsWithLegacySemantics] option controls this behavior difference.78//79//   - In v1, MarshalJSON and UnmarshalJSON methods are never called for Go map keys.80//     In contrast, in v2 a MarshalJSON or UnmarshalJSON method is eligible for81//     being called for Go map keys.82//     The [CallMethodsWithLegacySemantics] option controls this behavior difference.83//84//   - In v1, a Go map is marshaled in a deterministic order.85//     In contrast, in v2 a Go map is marshaled in a non-deterministic order.86//     The [jsonv2.Deterministic] option controls this behavior difference.87//88//   - In v1, JSON strings are encoded with HTML-specific or JavaScript-specific89//     characters being escaped. In contrast, in v2 JSON strings use the minimal90//     encoding and only escape if required by the JSON grammar.91//     The [jsontext.EscapeForHTML] and [jsontext.EscapeForJS] options92//     control this behavior difference.93//94//   - In v1, bytes of invalid UTF-8 within a string are silently replaced with95//     the Unicode replacement character. In contrast, in v2 the presence of96//     invalid UTF-8 results in an error. The [jsontext.AllowInvalidUTF8] option97//     controls this behavior difference.98//99//   - In v1, a JSON object with duplicate names is permitted.100//     In contrast, in v2 a JSON object with duplicate names results in an error.101//     The [jsontext.AllowDuplicateNames] option controls this behavior difference.102//103//   - In v1, when unmarshaling a JSON null into a non-empty Go value it will104//     inconsistently either zero out the value or do nothing.105//     In contrast, in v2 unmarshaling a JSON null will consistently and always106//     zero out the underlying Go value. The [MergeWithLegacySemantics] option107//     controls this behavior difference.108//109//   - In v1, when unmarshaling a JSON value into a non-zero Go value,110//     it merges into the original Go value for array elements, slice elements,111//     struct fields (but not map values),112//     pointer values, and interface values (only if a non-nil pointer).113//     In contrast, in v2 unmarshal merges into the Go value114//     for struct fields, map values, pointer values, and interface values.115//     In general, the v2 semantic merges when unmarshaling a JSON object,116//     otherwise it replaces the value. The [MergeWithLegacySemantics] option117//     controls this behavior difference.118//119//   - In v1, a [time.Duration] is represented as a JSON number containing120//     the decimal number of nanoseconds. In contrast, in v2 a [time.Duration]121//     has no default representation and results in a runtime error.122//     The [FormatDurationAsNano] option controls this behavior difference.123//     To explicitly specify a Go struct field to use a particular representation,124//     either the `format:nano` or `format:units` field option can be specified.125//     Field-specified options take precedence over caller-specified options.126//127//   - In v1, errors are never reported at runtime for Go struct types128//     that have some form of structural error (e.g., a malformed tag option).129//     In contrast, v2 reports a runtime error for Go types that are invalid130//     as they relate to JSON serialization. For example, a Go struct131//     with only unexported fields cannot be serialized.132//     The [ReportErrorsWithLegacySemantics] option controls this behavior difference.133//134// As mentioned, the entirety of v1 is implemented in terms of v2,135// where options are implicitly specified to opt into legacy behavior.136// For example, [Marshal] directly calls [jsonv2.Marshal] with [DefaultOptionsV1].137// Similarly, [Unmarshal] directly calls [jsonv2.Unmarshal] with [DefaultOptionsV1].138// The [DefaultOptionsV1] option represents the set of all options that specify139// default v1 behavior.140//141// For many of the behavior differences, there are Go struct field options142// that the author of a Go type can specify to control the behavior such that143// the type is represented identically in JSON under either v1 or v2 semantics.144//145// The availability of [DefaultOptionsV1] and [jsonv2.DefaultOptionsV2],146// where later options take precedence over former options allows for147// a gradual migration from v1 to v2. For example:148//149//   - jsonv1.Marshal(v)150//     uses default v1 semantics.151//152//   - jsonv2.Marshal(v, jsonv1.DefaultOptionsV1())153//     is semantically equivalent to jsonv1.Marshal154//     and thus uses default v1 semantics.155//156//   - jsonv2.Marshal(v, jsonv1.DefaultOptionsV1(), jsontext.AllowDuplicateNames(false))157//     uses mostly v1 semantics, but opts into one particular v2-specific behavior.158//159//   - jsonv2.Marshal(v, jsonv1.CallMethodsWithLegacySemantics(true))160//     uses mostly v2 semantics, but opts into one particular v1-specific behavior.161//162//   - jsonv2.Marshal(v, ..., jsonv2.DefaultOptionsV2())163//     is semantically equivalent to jsonv2.Marshal since164//     jsonv2.DefaultOptionsV2 overrides any options specified earlier165//     and thus uses default v2 semantics.166//167//   - jsonv2.Marshal(v)168//     uses default v2 semantics.169//170// All new usages of "json" in Go should use the v2 package,171// but the v1 package will forever remain supported.172package json173 174// TODO(https://go.dev/issue/71631): Update the "Migrating to v2" documentation175// with default v2 behavior for [time.Duration].176 177import (178	"encoding"179 180	"encoding/json/internal/jsonflags"181	"encoding/json/internal/jsonopts"182	"encoding/json/jsontext"183	jsonv2 "encoding/json/v2"184)185 186// Reference encoding, jsonv2, and jsontext packages to assist pkgsite187// in being able to hotlink references to those packages.188var (189	_ encoding.TextMarshaler190	_ encoding.TextUnmarshaler191	_ jsonv2.Options192	_ jsontext.Options193)194 195// Options are a set of options to configure the v2 "json" package196// to operate with v1 semantics for particular features.197// Values of this type can be passed to v2 functions like198// [jsonv2.Marshal] or [jsonv2.Unmarshal].199// Instead of referencing this type, use [jsonv2.Options].200//201// See the "Migrating to v2" section for guidance on how to migrate usage202// of "json" from using v1 to using v2 instead.203type Options = jsonopts.Options204 205// DefaultOptionsV1 is the full set of all options that define v1 semantics.206// It is equivalent to the following boolean options being set to true:207//208//   - [CallMethodsWithLegacySemantics]209//   - [FormatByteArrayAsArray]210//   - [FormatBytesWithLegacySemantics]211//   - [FormatDurationAsNano]212//   - [MatchCaseSensitiveDelimiter]213//   - [MergeWithLegacySemantics]214//   - [OmitEmptyWithLegacySemantics]215//   - [ParseBytesWithLooseRFC4648]216//   - [ParseTimeWithLooseRFC3339]217//   - [ReportErrorsWithLegacySemantics]218//   - [StringifyWithLegacySemantics]219//   - [UnmarshalArrayFromAnyLength]220//   - [jsonv2.Deterministic]221//   - [jsonv2.FormatNilMapAsNull]222//   - [jsonv2.FormatNilSliceAsNull]223//   - [jsonv2.MatchCaseInsensitiveNames]224//   - [jsontext.AllowDuplicateNames]225//   - [jsontext.AllowInvalidUTF8]226//   - [jsontext.EscapeForHTML]227//   - [jsontext.EscapeForJS]228//   - [jsontext.PreserveRawStrings]229//230// All other options are not present.231//232// The [Marshal] and [Unmarshal] functions in this package are233// semantically identical to calling the v2 equivalents with this option:234//235//	jsonv2.Marshal(v, jsonv1.DefaultOptionsV1())236//	jsonv2.Unmarshal(b, v, jsonv1.DefaultOptionsV1())237func DefaultOptionsV1() Options {238	return &jsonopts.DefaultOptionsV1239}240 241// CallMethodsWithLegacySemantics specifies that calling of type-provided242// marshal and unmarshal methods follow legacy semantics:243//244//   - When marshaling, a marshal method declared on a pointer receiver245//     is only called if the Go value is addressable.246//     Values obtained from an interface or map element are not addressable.247//     Values obtained from a pointer or slice element are addressable.248//     Values obtained from an array element or struct field inherit249//     the addressability of the parent. In contrast, the v2 semantic250//     is to always call marshal methods regardless of addressability.251//252//   - When marshaling or unmarshaling, the [Marshaler] or [Unmarshaler]253//     methods are ignored for map keys. However, [encoding.TextMarshaler]254//     or [encoding.TextUnmarshaler] are still callable.255//     In contrast, the v2 semantic is to serialize map keys256//     like any other value (with regard to calling methods),257//     which may include calling [Marshaler] or [Unmarshaler] methods,258//     where it is the implementation's responsibility to represent the259//     Go value as a JSON string (as required for JSON object names).260//261//   - When marshaling, if a map key value implements a marshal method262//     and is a nil pointer, then it is serialized as an empty JSON string.263//     In contrast, the v2 semantic is to report an error.264//265//   - When marshaling, if an interface type implements a marshal method266//     and the interface value is a nil pointer to a concrete type,267//     then the marshal method is always called.268//     In contrast, the v2 semantic is to never directly call methods269//     on interface values and to instead defer evaluation based upon270//     the underlying concrete value. Similar to non-interface values,271//     marshal methods are not called on nil pointers and272//     are instead serialized as a JSON null.273//274// This affects either marshaling or unmarshaling.275// The v1 default is true.276func CallMethodsWithLegacySemantics(v bool) Options {277	if v {278		return jsonflags.CallMethodsWithLegacySemantics | 1279	} else {280		return jsonflags.CallMethodsWithLegacySemantics | 0281	}282}283 284// FormatByteArrayAsArray specifies that a Go [N]byte is285// formatted as as a normal Go array in contrast to the v2 default of286// formatting [N]byte as using binary data encoding (RFC 4648).287// If a struct field has a `format` tag option,288// then the specified formatting takes precedence.289//290// This affects either marshaling or unmarshaling.291// The v1 default is true.292func FormatByteArrayAsArray(v bool) Options {293	if v {294		return jsonflags.FormatByteArrayAsArray | 1295	} else {296		return jsonflags.FormatByteArrayAsArray | 0297	}298}299 300// FormatBytesWithLegacySemantics specifies that handling of301// []~byte and [N]~byte types follow legacy semantics:302//303//   - A Go []~byte is to be treated as using some form of304//     binary data encoding (RFC 4648) in contrast to the v2 default305//     of only treating []byte as such. In particular, v2 does not306//     treat slices of named byte types as representing binary data.307//308//   - When marshaling, if a named byte implements a marshal method,309//     then the slice is serialized as a JSON array of elements,310//     each of which call the marshal method.311//312//   - When unmarshaling, if the input is a JSON array,313//     then unmarshal into the []~byte as if it were a normal Go slice.314//     In contrast, the v2 default is to report an error unmarshaling315//     a JSON array when expecting some form of binary data encoding.316//317// This affects either marshaling or unmarshaling.318// The v1 default is true.319func FormatBytesWithLegacySemantics(v bool) Options {320	if v {321		return jsonflags.FormatBytesWithLegacySemantics | 1322	} else {323		return jsonflags.FormatBytesWithLegacySemantics | 0324	}325}326 327// FormatDurationAsNano specifies that a [time.Duration] is328// formatted as a JSON number representing the number of nanoseconds329// in contrast to the v2 default of reporting an error.330// If a duration field has a `format` tag option,331// then the specified formatting takes precedence.332//333// This affects either marshaling or unmarshaling.334// The v1 default is true.335func FormatDurationAsNano(v bool) Options {336	// TODO(https://go.dev/issue/71631): Update documentation with v2 behavior.337	if v {338		return jsonflags.FormatDurationAsNano | 1339	} else {340		return jsonflags.FormatDurationAsNano | 0341	}342}343 344// MatchCaseSensitiveDelimiter specifies that underscores and dashes are345// not to be ignored when performing case-insensitive name matching which346// occurs under [jsonv2.MatchCaseInsensitiveNames] or the `case:ignore` tag option.347// Thus, case-insensitive name matching is identical to [strings.EqualFold].348// Use of this option diminishes the ability of case-insensitive matching349// to be able to match common case variants (e.g, "foo_bar" with "fooBar").350//351// This affects either marshaling or unmarshaling.352// The v1 default is true.353func MatchCaseSensitiveDelimiter(v bool) Options {354	if v {355		return jsonflags.MatchCaseSensitiveDelimiter | 1356	} else {357		return jsonflags.MatchCaseSensitiveDelimiter | 0358	}359}360 361// MergeWithLegacySemantics specifies that unmarshaling into a non-zero362// Go value follows legacy semantics:363//364//   - When unmarshaling a JSON null, this preserves the original Go value365//     if the kind is a bool, int, uint, float, string, array, or struct.366//     Otherwise, it zeros the Go value.367//     In contrast, the default v2 behavior is to consistently and always368//     zero the Go value when unmarshaling a JSON null into it.369//370//   - When unmarshaling a JSON value other than null, this merges into371//     the original Go value for array elements, slice elements,372//     struct fields (but not map values),373//     pointer values, and interface values (only if a non-nil pointer).374//     In contrast, the default v2 behavior is to merge into the Go value375//     for struct fields, map values, pointer values, and interface values.376//     In general, the v2 semantic merges when unmarshaling a JSON object,377//     otherwise it replaces the original value.378//379// This only affects unmarshaling and is ignored when marshaling.380// The v1 default is true.381func MergeWithLegacySemantics(v bool) Options {382	if v {383		return jsonflags.MergeWithLegacySemantics | 1384	} else {385		return jsonflags.MergeWithLegacySemantics | 0386	}387}388 389// OmitEmptyWithLegacySemantics specifies that the `omitempty` tag option390// follows a definition of empty where a field is omitted if the Go value is391// false, 0, a nil pointer, a nil interface value,392// or any empty array, slice, map, or string.393// This overrides the v2 semantic where a field is empty if the value394// marshals as a JSON null or an empty JSON string, object, or array.395//396// The v1 and v2 definitions of `omitempty` are practically the same for397// Go strings, slices, arrays, and maps. Usages of `omitempty` on398// Go bools, ints, uints floats, pointers, and interfaces should migrate to use399// the `omitzero` tag option, which omits a field if it is the zero Go value.400//401// This only affects marshaling and is ignored when unmarshaling.402// The v1 default is true.403func OmitEmptyWithLegacySemantics(v bool) Options {404	if v {405		return jsonflags.OmitEmptyWithLegacySemantics | 1406	} else {407		return jsonflags.OmitEmptyWithLegacySemantics | 0408	}409}410 411// ParseBytesWithLooseRFC4648 specifies that when parsing412// binary data encoded as "base32" or "base64",413// to ignore the presence of '\r' and '\n' characters.414// In contrast, the v2 default is to report an error in order to be415// strictly compliant with RFC 4648, section 3.3,416// which specifies that non-alphabet characters must be rejected.417//418// This only affects unmarshaling and is ignored when marshaling.419// The v1 default is true.420func ParseBytesWithLooseRFC4648(v bool) Options {421	if v {422		return jsonflags.ParseBytesWithLooseRFC4648 | 1423	} else {424		return jsonflags.ParseBytesWithLooseRFC4648 | 0425	}426}427 428// ParseTimeWithLooseRFC3339 specifies that a [time.Time]429// parses according to loose adherence to RFC 3339.430// In particular, it permits historically incorrect representations,431// allowing for deviations in hour format, sub-second separator,432// and timezone representation. In contrast, the default v2 behavior433// is to strictly comply with the grammar specified in RFC 3339.434//435// This only affects unmarshaling and is ignored when marshaling.436// The v1 default is true.437func ParseTimeWithLooseRFC3339(v bool) Options {438	if v {439		return jsonflags.ParseTimeWithLooseRFC3339 | 1440	} else {441		return jsonflags.ParseTimeWithLooseRFC3339 | 0442	}443}444 445// ReportErrorsWithLegacySemantics specifies that Marshal and Unmarshal446// should report errors with legacy semantics:447//448//   - When marshaling or unmarshaling, the returned error values are449//     usually of types such as [SyntaxError], [MarshalerError],450//     [UnsupportedTypeError], [UnsupportedValueError],451//     [InvalidUnmarshalError], or [UnmarshalTypeError].452//     In contrast, the v2 semantic is to always return errors as either453//     [jsonv2.SemanticError] or [jsontext.SyntacticError].454//455//   - When marshaling, if a user-defined marshal method reports an error,456//     it is always wrapped in a [MarshalerError], even if the error itself457//     is already a [MarshalerError], which may lead to multiple redundant458//     layers of wrapping. In contrast, the v2 semantic is to459//     always wrap an error within [jsonv2.SemanticError]460//     unless it is already a semantic error.461//462//   - When unmarshaling, if a user-defined unmarshal method reports an error,463//     it is never wrapped and reported verbatim. In contrast, the v2 semantic464//     is to always wrap an error within [jsonv2.SemanticError]465//     unless it is already a semantic error.466//467//   - When marshaling or unmarshaling, if a Go struct contains type errors468//     (e.g., conflicting names or malformed field tags), then such errors469//     are ignored and the Go struct uses a best-effort representation.470//     In contrast, the v2 semantic is to report a runtime error.471//472//   - When unmarshaling, the syntactic structure of the JSON input473//     is fully validated before performing the semantic unmarshaling474//     of the JSON data into the Go value. Practically speaking,475//     this means that JSON input with syntactic errors do not result476//     in any mutations of the target Go value. In contrast, the v2 semantic477//     is to perform a streaming decode and gradually unmarshal the JSON input478//     into the target Go value, which means that the Go value may be479//     partially mutated when a syntactic error is encountered.480//481//   - When unmarshaling, a semantic error does not immediately terminate the482//     unmarshal procedure, but rather evaluation continues.483//     When unmarshal returns, only the first semantic error is reported.484//     In contrast, the v2 semantic is to terminate unmarshal the moment485//     an error is encountered.486//487// This affects either marshaling or unmarshaling.488// The v1 default is true.489func ReportErrorsWithLegacySemantics(v bool) Options {490	if v {491		return jsonflags.ReportErrorsWithLegacySemantics | 1492	} else {493		return jsonflags.ReportErrorsWithLegacySemantics | 0494	}495}496 497// StringifyWithLegacySemantics specifies that the `string` tag option498// may stringify bools and string values. It only takes effect on fields499// where the top-level type is a bool, string, numeric kind, or a pointer to500// such a kind. Specifically, `string` will not stringify bool, string,501// or numeric kinds within a composite data type502// (e.g., array, slice, struct, map, or interface).503//504// When marshaling, such Go values are serialized as their usual505// JSON representation, but quoted within a JSON string.506// When unmarshaling, such Go values must be deserialized from507// a JSON string containing their usual JSON representation or508// Go number representation for that numeric kind.509// Note that the Go number grammar is a superset of the JSON number grammar.510// A JSON null quoted in a JSON string is a valid substitute for JSON null511// while unmarshaling into a Go value that `string` takes effect on.512//513// This affects either marshaling or unmarshaling.514// The v1 default is true.515func StringifyWithLegacySemantics(v bool) Options {516	if v {517		return jsonflags.StringifyWithLegacySemantics | 1518	} else {519		return jsonflags.StringifyWithLegacySemantics | 0520	}521}522 523// UnmarshalArrayFromAnyLength specifies that Go arrays can be unmarshaled524// from input JSON arrays of any length. If the JSON array is too short,525// then the remaining Go array elements are zeroed. If the JSON array526// is too long, then the excess JSON array elements are skipped over.527//528// This only affects unmarshaling and is ignored when marshaling.529// The v1 default is true.530func UnmarshalArrayFromAnyLength(v bool) Options {531	if v {532		return jsonflags.UnmarshalArrayFromAnyLength | 1533	} else {534		return jsonflags.UnmarshalArrayFromAnyLength | 0535	}536}537 538// unmarshalAnyWithRawNumber specifies that unmarshaling a JSON number into539// an empty Go interface should use the Number type instead of a float64.540func unmarshalAnyWithRawNumber(v bool) Options {541	if v {542		return jsonflags.UnmarshalAnyWithRawNumber | 1543	} else {544		return jsonflags.UnmarshalAnyWithRawNumber | 0545	}546}547 
codekingpro/portable-devtools · Team Ai