hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

remarshal.go (2090B)

    1 package transform
    2 
    3 import (
    4 	"bytes"
    5 	"strings"
    6 
    7 	"errors"
    8 
    9 	"github.com/gohugoio/hugo/parser"
   10 	"github.com/gohugoio/hugo/parser/metadecoders"
   11 	"github.com/spf13/cast"
   12 )
   13 
   14 // Remarshal is used in the Hugo documentation to convert configuration
   15 // examples from YAML to JSON, TOML (and possibly the other way around).
   16 // The is primarily a helper for the Hugo docs site.
   17 // It is not a general purpose YAML to TOML converter etc., and may
   18 // change without notice if it serves a purpose in the docs.
   19 // Format is one of json, yaml or toml.
   20 func (ns *Namespace) Remarshal(format string, data any) (string, error) {
   21 	var meta map[string]any
   22 
   23 	format = strings.TrimSpace(strings.ToLower(format))
   24 
   25 	mark, err := toFormatMark(format)
   26 	if err != nil {
   27 		return "", err
   28 	}
   29 
   30 	if m, ok := data.(map[string]any); ok {
   31 		meta = m
   32 	} else {
   33 		from, err := cast.ToStringE(data)
   34 		if err != nil {
   35 			return "", err
   36 		}
   37 
   38 		from = strings.TrimSpace(from)
   39 		if from == "" {
   40 			return "", nil
   41 		}
   42 
   43 		fromFormat := metadecoders.Default.FormatFromContentString(from)
   44 		if fromFormat == "" {
   45 			return "", errors.New("failed to detect format from content")
   46 		}
   47 
   48 		meta, err = metadecoders.Default.UnmarshalToMap([]byte(from), fromFormat)
   49 		if err != nil {
   50 			return "", err
   51 		}
   52 	}
   53 
   54 	// Make it so 1.0 float64 prints as 1 etc.
   55 	applyMarshalTypes(meta)
   56 
   57 	var result bytes.Buffer
   58 	if err := parser.InterfaceToConfig(meta, mark, &result); err != nil {
   59 		return "", err
   60 	}
   61 
   62 	return result.String(), nil
   63 }
   64 
   65 // The unmarshal/marshal dance is extremely type lossy, and we need
   66 // to make sure that integer types prints as "43" and not "43.0" in
   67 // all formats, hence this hack.
   68 func applyMarshalTypes(m map[string]any) {
   69 	for k, v := range m {
   70 		switch t := v.(type) {
   71 		case map[string]any:
   72 			applyMarshalTypes(t)
   73 		case float64:
   74 			i := int64(t)
   75 			if t == float64(i) {
   76 				m[k] = i
   77 			}
   78 		}
   79 	}
   80 }
   81 
   82 func toFormatMark(format string) (metadecoders.Format, error) {
   83 	if f := metadecoders.FormatFromString(format); f != "" {
   84 		return f, nil
   85 	}
   86 
   87 	return "", errors.New("failed to detect target data serialization format")
   88 }