vendor tsgo

This commit is contained in:
2026-07-09 16:50:43 -04:00
parent c06ea2e5a4
commit 98978e4930
5804 changed files with 1556156 additions and 101 deletions

View File

@@ -0,0 +1,217 @@
// Copyright 2023 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.
//go:build !goexperiment.jsonv2 || !go1.25
package jsonopts
import (
"github.com/go-json-experiment/json/internal"
"github.com/go-json-experiment/json/internal/jsonflags"
)
// Options is the common options type shared across json packages.
type Options interface {
// JSONOptions is exported so related json packages can implement Options.
JSONOptions(internal.NotForPublicUse)
}
// experimentalFormatTagSupporter is a special option method that allows
// [github.com/go-json-experiment/json.ExperimentalSupportFormatTag]
// to enable experimental `format` tag functionality at runtime.
type experimentalFormatTagSupporter interface{ ExperimentalSupportFormatTag() bool }
// Struct is the combination of all options in struct form.
// This is efficient to pass down the call stack and to query.
type Struct struct {
Flags jsonflags.Flags
CoderValues
ArshalValues
}
type CoderValues struct {
Indent string // jsonflags.Indent
IndentPrefix string // jsonflags.IndentPrefix
ByteLimit int64 // jsonflags.ByteLimit
DepthLimit int // jsonflags.DepthLimit
}
type ArshalValues struct {
// The Marshalers and Unmarshalers fields use the any type to avoid a
// concrete dependency on *json.Marshalers and *json.Unmarshalers,
// which would in turn create a dependency on the "reflect" package.
Marshalers any // jsonflags.Marshalers
Unmarshalers any // jsonflags.Unmarshalers
Format string // valid if jsonflags.FormatTag is set
}
// DefaultOptionsV2 is the set of all options that define default v2 behavior.
var DefaultOptionsV2 = Struct{
Flags: jsonflags.Flags{
Presence: uint64(jsonflags.DefaultV1Flags),
Values: uint64(0), // all flags in DefaultV1Flags are false
},
}
// DefaultOptionsV1 is the set of all options that define default v1 behavior.
var DefaultOptionsV1 = Struct{
Flags: jsonflags.Flags{
Presence: uint64(jsonflags.DefaultV1Flags),
Values: uint64(jsonflags.DefaultV1Flags), // all flags in DefaultV1Flags are true
},
}
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") }
func GetOption[T any](opts Options, setter func(T) Options) (T, bool) {
// Collapse the options to *Struct to simplify lookup.
structOpts, ok := opts.(*Struct)
if !ok {
var structOpts2 Struct
structOpts2.Join(opts)
structOpts = &structOpts2
}
// Lookup the option based on the return value of the setter.
var zero T
switch opt := setter(zero).(type) {
case jsonflags.Bools:
v := structOpts.Flags.Get(opt)
ok := structOpts.Flags.Has(opt)
if !ok && opt == jsonflags.StringifyNumbers && structOpts.Flags.Get(jsonflags.StringTag) {
return any(true).(T), true // check also whether the option is specified via a `string` tag
}
return any(v).(T), ok
case experimentalFormatTagSupporter:
v := structOpts.Flags.Get(jsonflags.FormatTagSupported)
ok := structOpts.Flags.Has(jsonflags.FormatTagSupported)
return any(v).(T), ok
case Indent:
if !structOpts.Flags.Has(jsonflags.Indent) {
return zero, false
}
return any(structOpts.Indent).(T), true
case IndentPrefix:
if !structOpts.Flags.Has(jsonflags.IndentPrefix) {
return zero, false
}
return any(structOpts.IndentPrefix).(T), true
case ByteLimit:
if !structOpts.Flags.Has(jsonflags.ByteLimit) {
return zero, false
}
return any(structOpts.ByteLimit).(T), true
case DepthLimit:
if !structOpts.Flags.Has(jsonflags.DepthLimit) {
return zero, false
}
return any(structOpts.DepthLimit).(T), true
default:
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) Struct { panic("unknown option") }
func (dst *Struct) Join(srcs ...Options) {
for _, src := range srcs {
switch src := src.(type) {
case nil:
continue
case jsonflags.Bools:
dst.Flags.Set(src)
case experimentalFormatTagSupporter:
if src.ExperimentalSupportFormatTag() {
dst.Flags.Set(jsonflags.FormatTagSupported | 1)
} else {
dst.Flags.Set(jsonflags.FormatTagSupported | 0)
}
case Indent:
dst.Flags.Set(jsonflags.Multiline | jsonflags.Indent | 1)
dst.Indent = string(src)
case IndentPrefix:
dst.Flags.Set(jsonflags.Multiline | jsonflags.IndentPrefix | 1)
dst.IndentPrefix = string(src)
case ByteLimit:
dst.Flags.Set(jsonflags.ByteLimit | 1)
dst.ByteLimit = int64(src)
case DepthLimit:
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) {
dst.Indent = src.Indent
}
if src.Flags.Has(jsonflags.IndentPrefix) {
dst.IndentPrefix = src.IndentPrefix
}
if src.Flags.Has(jsonflags.ByteLimit) {
dst.ByteLimit = src.ByteLimit
}
if src.Flags.Has(jsonflags.DepthLimit) {
dst.DepthLimit = src.DepthLimit
}
if src.Flags.Has(jsonflags.Marshalers) {
dst.Marshalers = src.Marshalers
}
if src.Flags.Has(jsonflags.Unmarshalers) {
dst.Unmarshalers = src.Unmarshalers
}
if src.Flags.Has(jsonflags.FormatTag) {
dst.Format = src.Format
}
}
default:
*dst = JoinUnknownOption(*dst, src)
}
}
}
// InitializeMultiline sets default options implied by Multiline.
func (s *Struct) InitializeMultiline() {
if !s.Flags.Has(jsonflags.SpaceAfterColon) {
s.Flags.Set(jsonflags.SpaceAfterColon | 1)
}
if !s.Flags.Has(jsonflags.SpaceAfterComma) {
s.Flags.Set(jsonflags.SpaceAfterComma | 0)
}
if !s.Flags.Has(jsonflags.Indent) {
s.Flags.Set(jsonflags.Indent | 1)
s.Indent = "\t"
}
}
// ChangedWhitespace reports whether whitespace values have changed.
func ChangedWhitespace(s1, s2 Struct) bool {
return s1.Flags.Get(jsonflags.Multiline) != s2.Flags.Get(jsonflags.Multiline) ||
s1.Flags.Get(jsonflags.SpaceAfterColon) != s2.Flags.Get(jsonflags.SpaceAfterColon) ||
s1.Flags.Get(jsonflags.SpaceAfterComma) != s2.Flags.Get(jsonflags.SpaceAfterComma) ||
(s2.Flags.Get(jsonflags.Multiline) && (s1.Indent != s2.Indent || s1.IndentPrefix != s2.IndentPrefix))
}
type (
Indent string // jsontext.WithIndent
IndentPrefix string // jsontext.WithIndentPrefix
ByteLimit int64 // jsontext.WithByteLimit
DepthLimit int // jsontext.WithDepthLimit
// type for jsonflags.Marshalers declared in "json" package
// type for jsonflags.Unmarshalers declared in "json" package
)
func (Indent) JSONOptions(internal.NotForPublicUse) {}
func (IndentPrefix) JSONOptions(internal.NotForPublicUse) {}
func (ByteLimit) JSONOptions(internal.NotForPublicUse) {}
func (DepthLimit) JSONOptions(internal.NotForPublicUse) {}

View File

@@ -0,0 +1,124 @@
// 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.
//go:build !goexperiment.jsonv2 || !go1.25
package jsonopts
// 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 "github.com/go-json-experiment/json" 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 "github.com/go-json-experiment/json"
// 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 "github.com/go-json-experiment/json" experiment
// but support for it was removed (see https://go.dev/issue/79071) for the
// initial release of "github.com/go-json-experiment/json" 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 "github.com/go-json-experiment/json" 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 "github.com/go-json-experiment/json" 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
}
}