add forked version of encoding/json with html escape disabled
- modified all local packages to use this fork
This commit is contained in:
153
pkg/encoders/json/v2_inject.go
Normal file
153
pkg/encoders/json/v2_inject.go
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2024 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
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"encoding/json/internal"
|
||||
"encoding/json/jsontext"
|
||||
jsonv2 "encoding/json/v2"
|
||||
)
|
||||
|
||||
// Inject functionality into v2 to properly handle v1 types.
|
||||
func init() {
|
||||
internal.TransformMarshalError = transformMarshalError
|
||||
internal.TransformUnmarshalError = transformUnmarshalError
|
||||
internal.NewMarshalerError = func(val any, err error, funcName string) error {
|
||||
return &MarshalerError{reflect.TypeOf(val), err, funcName}
|
||||
}
|
||||
|
||||
internal.NewRawNumber = func() any { return new(Number) }
|
||||
internal.RawNumberOf = func(b []byte) any { return Number(b) }
|
||||
}
|
||||
|
||||
func transformMarshalError(root any, err error) error {
|
||||
// Historically, errors returned from Marshal methods were wrapped
|
||||
// in a [MarshalerError]. This is directly performed by the v2 package
|
||||
// via the injected [internal.NewMarshalerError] constructor
|
||||
// while operating under [ReportErrorsWithLegacySemantics].
|
||||
// Note that errors from a Marshal method were always wrapped,
|
||||
// even if wrapped for multiple layers.
|
||||
if err, ok := err.(*jsonv2.SemanticError); err != nil {
|
||||
if err.Err == nil {
|
||||
// Historically, this was only reported for unserializable types
|
||||
// like complex numbers, channels, functions, and unsafe.Pointers.
|
||||
return &UnsupportedTypeError{Type: err.GoType}
|
||||
} else {
|
||||
// Historically, this was only reported for NaN or ±Inf values
|
||||
// and cycles detected in the value.
|
||||
// The Val used to be populated with the reflect.Value,
|
||||
// but this is no longer supported.
|
||||
errStr := err.Err.Error()
|
||||
if err.Err == internal.ErrCycle && err.GoType != nil {
|
||||
errStr += " via " + err.GoType.String()
|
||||
}
|
||||
errStr = strings.TrimPrefix(errStr, "unsupported value: ")
|
||||
return &UnsupportedValueError{Str: errStr}
|
||||
}
|
||||
} else if ok {
|
||||
return (*UnsupportedValueError)(nil)
|
||||
}
|
||||
if err, _ := err.(*MarshalerError); err != nil {
|
||||
err.Err = transformSyntacticError(err.Err)
|
||||
return err
|
||||
}
|
||||
return transformSyntacticError(err)
|
||||
}
|
||||
|
||||
func transformUnmarshalError(root any, err error) error {
|
||||
// Historically, errors from Unmarshal methods were never wrapped and
|
||||
// returned verbatim while operating under [ReportErrorsWithLegacySemantics].
|
||||
if err, ok := err.(*jsonv2.SemanticError); err != nil {
|
||||
if err.Err == internal.ErrNonNilReference {
|
||||
return &InvalidUnmarshalError{err.GoType}
|
||||
}
|
||||
if err.Err == jsonv2.ErrUnknownName {
|
||||
return fmt.Errorf("json: unknown field %q", err.JSONPointer.LastToken())
|
||||
}
|
||||
|
||||
// Historically, UnmarshalTypeError has always been inconsistent
|
||||
// about how it reported position information.
|
||||
//
|
||||
// The Struct field now points to the root type,
|
||||
// rather than some intermediate struct in the path.
|
||||
// This better matches the original intent of the field based
|
||||
// on how the Error message was formatted.
|
||||
//
|
||||
// For a representation closer to the historical representation,
|
||||
// we switch the '/'-delimited representation of a JSON pointer
|
||||
// to use a '.'-delimited representation. This may be ambiguous,
|
||||
// but the prior representation was always ambiguous as well.
|
||||
// Users that care about precise positions should use v2 errors
|
||||
// by disabling [ReportErrorsWithLegacySemantics].
|
||||
//
|
||||
// The introduction of a Err field is new to the v1-to-v2 migration
|
||||
// and allows us to preserve stronger error information
|
||||
// that may be surfaced by the v2 package.
|
||||
//
|
||||
// See https://go.dev/issue/43126
|
||||
var value string
|
||||
switch err.JSONKind {
|
||||
case 'n', '"', '0':
|
||||
value = err.JSONKind.String()
|
||||
case 'f', 't':
|
||||
value = "bool"
|
||||
case '[', ']':
|
||||
value = "array"
|
||||
case '{', '}':
|
||||
value = "object"
|
||||
}
|
||||
if len(err.JSONValue) > 0 {
|
||||
isStrconvError := err.Err == strconv.ErrRange || err.Err == strconv.ErrSyntax
|
||||
isNumericKind := func(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
|
||||
reflect.Float32, reflect.Float64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if isStrconvError && isNumericKind(err.GoType) {
|
||||
value = "number"
|
||||
if err.JSONKind == '"' {
|
||||
err.JSONValue, _ = jsontext.AppendUnquote(nil, err.JSONValue)
|
||||
}
|
||||
err.Err = nil
|
||||
}
|
||||
value += " " + string(err.JSONValue)
|
||||
}
|
||||
var rootName string
|
||||
if t := reflect.TypeOf(root); t != nil && err.JSONPointer != "" {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
rootName = t.Name()
|
||||
}
|
||||
fieldPath := string(err.JSONPointer)
|
||||
fieldPath = strings.TrimPrefix(fieldPath, "/")
|
||||
fieldPath = strings.ReplaceAll(fieldPath, "/", ".")
|
||||
return &UnmarshalTypeError{
|
||||
Value: value,
|
||||
Type: err.GoType,
|
||||
Offset: err.ByteOffset,
|
||||
Struct: rootName,
|
||||
Field: fieldPath,
|
||||
Err: transformSyntacticError(err.Err),
|
||||
}
|
||||
} else if ok {
|
||||
return (*UnmarshalTypeError)(nil)
|
||||
}
|
||||
return transformSyntacticError(err)
|
||||
}
|
||||
Reference in New Issue
Block a user