Source file src/encoding/json/internal/jsonopts/options_format.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.jsonv2
     6  
     7  package jsonopts
     8  
     9  // NOTE: While [ExperimentalSupportFormatTag] is exported,
    10  // it is in an internal package and thus inaccessible for public use.
    11  //
    12  // The [github.com/go-json-experiment/json] module is kept in sync
    13  // with the Go standard standard library and will expose this option
    14  // in a way that public code can now directly reference.
    15  
    16  type supportFormatTag struct {
    17  	Options
    18  	v bool
    19  }
    20  
    21  var (
    22  	enableFormatTag  = supportFormatTag{v: true}
    23  	disableFormatTag = supportFormatTag{v: false}
    24  )
    25  
    26  // ExperimentalSupportFormatTag is a marker method that is specially
    27  // recognized by the "encoding/json/v2" runtime.
    28  func (o *supportFormatTag) ExperimentalSupportFormatTag() bool {
    29  	return o.v
    30  }
    31  
    32  // ExperimentalSupportFormatTag enables support for the `format` tag.
    33  //
    34  // WARNING: This is an experimental feature and will be removed in the future
    35  // as either a failed experiment or be formally included in "encoding/json/v2"
    36  // in some semantically similar form, in which case, users of this option
    37  // must migrate to the officially supported feature.
    38  //
    39  // The `format` tag was originally part of the "encoding/json/v2" experiment
    40  // but support for it was removed (see https://go.dev/issue/79071) for the
    41  // initial release of "encoding/json/v2" in light of the anticipation that
    42  // the Go language might support typed struct tags (https://go.dev/issue/74472).
    43  //
    44  // Typed struct tags are a more expressive and type-safe way to express format
    45  // attributes than the bespoke `format` tag option that implements a miniature
    46  // domain-specific language (DSL) within the "json" package itself.
    47  //
    48  // While "encoding/json/v2" was in the experimental phase,
    49  // some users were already depending on the `format` tag option.
    50  // This experimental option exists to provide a temporary workaround
    51  // until the (hopeful) inclusion of typed struct tags and support for
    52  // formatting directives in "encoding/json/v2" using that language mechanism.
    53  //
    54  // This option enables support for the `format` tag option, which specifies
    55  // a format flag used to specialize the formatting of the field value.
    56  // The option is a key-value pair specified as "format:value" where
    57  // the value must be either a literal consisting of letters and numbers
    58  // (e.g., `format:RFC3339`) or a single-quoted string literal
    59  // (e.g., `format:'2006-01-02'`). The interpretation of the format flag
    60  // is determined by the struct field type.
    61  //
    62  // Go types with alternative representations are as follows:
    63  //
    64  //   - A Go []byte or [N]byte is usually represented as a JSON string
    65  //     containing the binary value encoded using RFC 4648.
    66  //     If the format is "base64" or unspecified, then this uses RFC 4648, section 4.
    67  //     If the format is "base64url", then this uses RFC 4648, section 5.
    68  //     If the format is "base32", then this uses RFC 4648, section 6.
    69  //     If the format is "base32hex", then this uses RFC 4648, section 7.
    70  //     If the format is "base16" or "hex", then this uses RFC 4648, section 8.
    71  //     If the format is "array", then the bytes value is represented as a JSON array
    72  //     where each element recursively uses the JSON representation of each byte.
    73  //
    74  //   - A Go float is usually represented as a JSON number.
    75  //     If the format is "nonfinite", then NaN, +Inf, and -Inf are represented as
    76  //     the JSON strings "NaN", "Infinity", and "-Infinity", respectively.
    77  //     Without the use of this format, such string values result in a [SemanticError].
    78  //
    79  //   - A nil Go map is usually encoded using an empty JSON object.
    80  //     If the format is "emitnull", then a nil map is encoded as a JSON null.
    81  //     If the format is "emitempty", then a nil map is encoded as an empty JSON object,
    82  //     regardless of whether [FormatNilMapAsNull] is specified.
    83  //
    84  //   - A nil Go slice is usually encoded using an empty JSON array.
    85  //     If the format is "emitnull", then a nil slice is encoded as a JSON null.
    86  //     If the format is "emitempty", then a nil slice is encoded as an empty JSON array,
    87  //     regardless of whether [FormatNilSliceAsNull] is specified.
    88  //
    89  //   - A Go pointer usually uses the JSON representation of the underlying value.
    90  //     The format is forwarded to the marshaling and unmarshaling of the underlying type.
    91  //
    92  //   - A Go [time.Time] is usually represented as a JSON string containing
    93  //     the timestamp formatted in RFC 3339 with nanosecond precision.
    94  //     If the format matches one of the format constants declared
    95  //     in the time package (e.g., RFC1123), then that format is used.
    96  //     If the format is "unix", "unixmilli", "unixmicro", or "unixnano",
    97  //     then the timestamp is represented as a possibly fractional JSON number
    98  //     of the number of seconds (or milliseconds, microseconds, or nanoseconds)
    99  //     since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC.
   100  //     To avoid a fractional component when encoding,
   101  //     round the timestamp to the relevant unit.
   102  //     Otherwise if non-empty, the format is used as-is and
   103  //     encoded using [time.Time.Format] and
   104  //     decoded using [time.Time.Parse].
   105  //
   106  //   - A Go [time.Duration] usually has no default representation.
   107  //     If the format is "sec", "milli", "micro", or "nano",
   108  //     then the duration is represented as a possibly fractional JSON number
   109  //     of the number of seconds (or milliseconds, microseconds, or nanoseconds).
   110  //     To avoid a fractional component when encoding,
   111  //     round the duration to the relevant unit.
   112  //     If the format is "units", it is represented as a JSON string
   113  //     encoded using [time.Duration.String] and decoded using [time.ParseDuration]
   114  //     (e.g., "1h30m" for 1 hour 30 minutes).
   115  //     If the format is "iso8601", it is represented as a JSON string using the
   116  //     ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes)
   117  //     using only accurate units of hours, minutes, and seconds.
   118  func ExperimentalSupportFormatTag(v bool) Options {
   119  	if v {
   120  		return &enableFormatTag
   121  	} else {
   122  		return &disableFormatTag
   123  	}
   124  }
   125  

View as plain text