165 lines
4.8 KiB
Go
165 lines
4.8 KiB
Go
|
// Copyright 2020-2021 Buf Technologies, Inc.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
// Package encoding provides encoding utilities.
|
||
|
package encoding
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
|
||
|
"go.uber.org/multierr"
|
||
|
"gopkg.in/yaml.v3"
|
||
|
)
|
||
|
|
||
|
// UnmarshalJSONStrict unmarshals the data as JSON, returning a user error on failure.
|
||
|
//
|
||
|
// If the data length is 0, this is a no-op.
|
||
|
func UnmarshalJSONStrict(data []byte, v interface{}) error {
|
||
|
if len(data) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
jsonDecoder := json.NewDecoder(bytes.NewReader(data))
|
||
|
jsonDecoder.DisallowUnknownFields()
|
||
|
if err := jsonDecoder.Decode(v); err != nil {
|
||
|
return fmt.Errorf("could not unmarshal as JSON: %v", err)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalYAMLStrict unmarshals the data as YAML, returning a user error on failure.
|
||
|
//
|
||
|
// If the data length is 0, this is a no-op.
|
||
|
func UnmarshalYAMLStrict(data []byte, v interface{}) error {
|
||
|
if len(data) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
yamlDecoder := NewYAMLDecoderStrict(bytes.NewReader(data))
|
||
|
if err := yamlDecoder.Decode(v); err != nil {
|
||
|
return fmt.Errorf("could not unmarshal as YAML: %v", err)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalJSONOrYAMLStrict unmarshals the data as JSON or YAML in order, returning
|
||
|
// a user error with both errors on failure.
|
||
|
//
|
||
|
// If the data length is 0, this is a no-op.
|
||
|
func UnmarshalJSONOrYAMLStrict(data []byte, v interface{}) error {
|
||
|
if len(data) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
if jsonErr := UnmarshalJSONStrict(data, v); jsonErr != nil {
|
||
|
if yamlErr := UnmarshalYAMLStrict(data, v); yamlErr != nil {
|
||
|
return errors.New(jsonErr.Error() + "\n" + yamlErr.Error())
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalJSONNonStrict unmarshals the data as JSON, returning a user error on failure.
|
||
|
//
|
||
|
// If the data length is 0, this is a no-op.
|
||
|
func UnmarshalJSONNonStrict(data []byte, v interface{}) error {
|
||
|
if len(data) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
jsonDecoder := json.NewDecoder(bytes.NewReader(data))
|
||
|
if err := jsonDecoder.Decode(v); err != nil {
|
||
|
return fmt.Errorf("could not unmarshal as JSON: %v", err)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalYAMLNonStrict unmarshals the data as YAML, returning a user error on failure.
|
||
|
//
|
||
|
// If the data length is 0, this is a no-op.
|
||
|
func UnmarshalYAMLNonStrict(data []byte, v interface{}) error {
|
||
|
if len(data) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
yamlDecoder := NewYAMLDecoderNonStrict(bytes.NewReader(data))
|
||
|
if err := yamlDecoder.Decode(v); err != nil {
|
||
|
return fmt.Errorf("could not unmarshal as YAML: %v", err)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalJSONOrYAMLNonStrict unmarshals the data as JSON or YAML in order, returning
|
||
|
// a user error with both errors on failure.
|
||
|
//
|
||
|
// If the data length is 0, this is a no-op.
|
||
|
func UnmarshalJSONOrYAMLNonStrict(data []byte, v interface{}) error {
|
||
|
if len(data) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
if jsonErr := UnmarshalJSONNonStrict(data, v); jsonErr != nil {
|
||
|
if yamlErr := UnmarshalYAMLNonStrict(data, v); yamlErr != nil {
|
||
|
return multierr.Append(jsonErr, yamlErr)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// GetJSONStringOrStringValue returns the JSON string for the RawMessage if the
|
||
|
// RawMessage is a string, and the raw value as a string otherwise.
|
||
|
//
|
||
|
// If the RawMessage is empty, this returns "".
|
||
|
func GetJSONStringOrStringValue(rawMessage json.RawMessage) string {
|
||
|
if len(rawMessage) == 0 {
|
||
|
return ""
|
||
|
}
|
||
|
var s string
|
||
|
if err := json.Unmarshal(rawMessage, &s); err == nil {
|
||
|
return s
|
||
|
}
|
||
|
return string(rawMessage)
|
||
|
}
|
||
|
|
||
|
// MarshalYAML marshals the given value into YAML.
|
||
|
func MarshalYAML(v interface{}) (_ []byte, retErr error) {
|
||
|
buffer := bytes.NewBuffer(nil)
|
||
|
yamlEncoder := NewYAMLEncoder(buffer)
|
||
|
defer func() {
|
||
|
retErr = multierr.Append(retErr, yamlEncoder.Close())
|
||
|
}()
|
||
|
if err := yamlEncoder.Encode(v); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return buffer.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
// NewYAMLEncoder creates a new YAML encoder reader from the Writer.
|
||
|
// The encoder must be closed after use.
|
||
|
func NewYAMLEncoder(writer io.Writer) *yaml.Encoder {
|
||
|
yamlEncoder := yaml.NewEncoder(writer)
|
||
|
yamlEncoder.SetIndent(2)
|
||
|
return yamlEncoder
|
||
|
}
|
||
|
|
||
|
// NewYAMLDecoderStrict creates a new YAML decoder from the reader.
|
||
|
func NewYAMLDecoderStrict(reader io.Reader) *yaml.Decoder {
|
||
|
yamlDecoder := yaml.NewDecoder(reader)
|
||
|
yamlDecoder.KnownFields(true)
|
||
|
return yamlDecoder
|
||
|
}
|
||
|
|
||
|
// NewYAMLDecoderNonStrict creates a new YAML decoder from the reader.
|
||
|
func NewYAMLDecoderNonStrict(reader io.Reader) *yaml.Decoder {
|
||
|
return yaml.NewDecoder(reader)
|
||
|
}
|