123 lines
6.0 KiB
Go
123 lines
6.0 KiB
Go
// Copyright 2026 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.
|
|
|
|
package json
|
|
|
|
// NOTE: While [ExperimentalSupportFormatTag] is exported,
|
|
// it is in an internal package and thus inaccessible for public use.
|
|
//
|
|
// The [github.com/go-json-experiment/json] module is kept in sync
|
|
// with the Go standard standard library and will expose this option
|
|
// in a way that public code can now directly reference.
|
|
|
|
type supportFormatTag struct {
|
|
Options
|
|
v bool
|
|
}
|
|
|
|
var (
|
|
enableFormatTag = supportFormatTag{v: true}
|
|
disableFormatTag = supportFormatTag{v: false}
|
|
)
|
|
|
|
// ExperimentalSupportFormatTag is a marker method that is specially
|
|
// recognized by the "encoding/json/v2" runtime.
|
|
func (o *supportFormatTag) ExperimentalSupportFormatTag() bool {
|
|
return o.v
|
|
}
|
|
|
|
// ExperimentalSupportFormatTag enables support for the `format` tag.
|
|
//
|
|
// WARNING: This is an experimental feature and will be removed in the future
|
|
// as either a failed experiment or be formally included in "encoding/json/v2"
|
|
// in some semantically similar form, in which case, users of this option
|
|
// must migrate to the officially supported feature.
|
|
//
|
|
// The `format` tag was originally part of the "encoding/json/v2" experiment
|
|
// but support for it was removed (see https://go.dev/issue/79071) for the
|
|
// initial release of "encoding/json/v2" in light of the anticipation that
|
|
// the Go language might support typed struct tags (https://go.dev/issue/74472).
|
|
//
|
|
// Typed struct tags are a more expressive and type-safe way to express format
|
|
// attributes than the bespoke `format` tag option that implements a miniature
|
|
// domain-specific language (DSL) within the "json" package itself.
|
|
//
|
|
// While "encoding/json/v2" was in the experimental phase,
|
|
// some users were already depending on the `format` tag option.
|
|
// This experimental option exists to provide a temporary workaround
|
|
// until the (hopeful) inclusion of typed struct tags and support for
|
|
// formatting directives in "encoding/json/v2" using that language mechanism.
|
|
//
|
|
// This option enables support for the `format` tag option, which 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.
|
|
//
|
|
// Go types with alternative representations are as follows:
|
|
//
|
|
// - A Go []byte or [N]byte is usually represented 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 represented as a JSON array
|
|
// where each element recursively uses the JSON representation of each byte.
|
|
//
|
|
// - A Go float is usually represented as a JSON number.
|
|
// If the format is "nonfinite", then NaN, +Inf, and -Inf are represented as
|
|
// the JSON strings "NaN", "Infinity", and "-Infinity", respectively.
|
|
// Without the use of this format, such string values result in a [SemanticError].
|
|
//
|
|
// - A nil Go map is usually encoded using an empty JSON object.
|
|
// 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.
|
|
//
|
|
// - A nil Go slice is usually encoded using an empty 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.
|
|
//
|
|
// - A Go pointer usually uses the JSON representation of the underlying value.
|
|
// The format is forwarded to the marshaling and unmarshaling of the underlying type.
|
|
//
|
|
// - A Go [time.Time] is usually represented 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 represented 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 when encoding,
|
|
// round the timestamp to the relevant unit.
|
|
// Otherwise if non-empty, the format is used as-is and
|
|
// encoded using [time.Time.Format] and
|
|
// decoded using [time.Time.Parse].
|
|
//
|
|
// - A Go [time.Duration] usually has no default representation.
|
|
// If the format is "sec", "milli", "micro", or "nano",
|
|
// then the duration is represented as a possibly fractional JSON number
|
|
// of the number of seconds (or milliseconds, microseconds, or nanoseconds).
|
|
// To avoid a fractional component when encoding,
|
|
// round the duration to the relevant unit.
|
|
// If the format is "units", it is represented as a JSON string
|
|
// encoded using [time.Duration.String] and decoded using [time.ParseDuration]
|
|
// (e.g., "1h30m" for 1 hour 30 minutes).
|
|
// If the format is "iso8601", it is represented 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.
|
|
func ExperimentalSupportFormatTag(v bool) Options {
|
|
if v {
|
|
return &enableFormatTag
|
|
} else {
|
|
return &disableFormatTag
|
|
}
|
|
}
|