mirror of
https://github.com/johnkerl/miller.git
synced 2026-01-23 02:14:13 +00:00
* Update package version * Update makefile targets * Update readme packages * Remaining old packages via rg/sd
185 lines
5.2 KiB
Go
185 lines
5.2 KiB
Go
// ================================================================
|
|
// See mlrval_json.go for details. This is the unmarshal/marshal solely for Mlrmap.
|
|
// ================================================================
|
|
|
|
package mlrval
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/johnkerl/miller/v6/pkg/colorizer"
|
|
"github.com/johnkerl/miller/v6/pkg/lib"
|
|
)
|
|
|
|
// ----------------------------------------------------------------
|
|
func (mlrmap *Mlrmap) MarshalJSON(
|
|
jsonFormatting TJSONFormatting,
|
|
outputIsStdout bool,
|
|
) (string, error) {
|
|
var buffer bytes.Buffer
|
|
s, err := mlrmap.marshalJSONAux(jsonFormatting, 1, outputIsStdout)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
buffer.WriteString(s)
|
|
// Do not write the final newline here, so the caller can write commas
|
|
// in the right place if desired.
|
|
// buffer.WriteString("\n")
|
|
return buffer.String(), nil
|
|
}
|
|
|
|
// For a map we only write from opening curly brace to closing curly brace. In
|
|
// nested-map contexts, mlrmap particular map might be written with a comma
|
|
// immediately after its closing curly brace, or a newline, and only the caller
|
|
// can know that.
|
|
//
|
|
// The element nesting depth is how deeply our element should be indented. Our
|
|
// closing curly brace is indented one less than that. For example, a
|
|
// root-level record '{"a":1,"b":2}' should be formatted as
|
|
//
|
|
// {
|
|
// "a": 1, <-- element nesting depth is 1 for root-level map
|
|
// "b": 2 <-- element nesting depth is 1 for root-level map
|
|
// } <-- closing curly brace nesting depth is 0 for root-level map
|
|
|
|
func (mlrmap *Mlrmap) marshalJSONAux(
|
|
jsonFormatting TJSONFormatting,
|
|
elementNestingDepth int,
|
|
outputIsStdout bool,
|
|
) (string, error) {
|
|
if jsonFormatting == JSON_MULTILINE {
|
|
return mlrmap.marshalJSONAuxMultiline(jsonFormatting, elementNestingDepth, outputIsStdout)
|
|
} else if jsonFormatting == JSON_SINGLE_LINE {
|
|
return mlrmap.marshalJSONAuxSingleLine(jsonFormatting, elementNestingDepth, outputIsStdout)
|
|
} else {
|
|
lib.InternalCodingErrorIf(true)
|
|
return "", nil // not reached
|
|
}
|
|
}
|
|
|
|
func (mlrmap *Mlrmap) marshalJSONAuxMultiline(
|
|
jsonFormatting TJSONFormatting,
|
|
elementNestingDepth int,
|
|
outputIsStdout bool,
|
|
) (string, error) {
|
|
var buffer bytes.Buffer
|
|
|
|
buffer.WriteString("{")
|
|
// Write empty map as '{}'. For anything else, opening curly brace in a
|
|
// line of its own, one key-value pair per line, closing curly brace on a
|
|
// line of its own.
|
|
if mlrmap.Head != nil {
|
|
buffer.WriteString("\n")
|
|
}
|
|
|
|
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
|
|
// Write the key which is necessarily string-valued in Miller, and in
|
|
// JSON for that matter :)
|
|
for i := 0; i < elementNestingDepth; i++ {
|
|
buffer.WriteString(JSON_INDENT_STRING)
|
|
}
|
|
encoded := string(millerJSONEncodeString(pe.Key))
|
|
colorized := colorizer.MaybeColorizeKey(encoded, outputIsStdout)
|
|
buffer.WriteString(colorized)
|
|
buffer.WriteString(": ")
|
|
|
|
// Write the value which is a mlrval
|
|
valueString, err := pe.Value.marshalJSONAux(jsonFormatting, elementNestingDepth+1, outputIsStdout)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
_, err = buffer.WriteString(valueString)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if pe.Next != nil {
|
|
buffer.WriteString(",")
|
|
}
|
|
buffer.WriteString("\n")
|
|
}
|
|
|
|
// Write empty map as '{}'.
|
|
if mlrmap.Head != nil {
|
|
for i := 0; i < elementNestingDepth-1; i++ {
|
|
buffer.WriteString(JSON_INDENT_STRING)
|
|
}
|
|
}
|
|
buffer.WriteString("}")
|
|
|
|
return buffer.String(), nil
|
|
}
|
|
|
|
func (mlrmap *Mlrmap) marshalJSONAuxSingleLine(
|
|
jsonFormatting TJSONFormatting,
|
|
elementNestingDepth int,
|
|
outputIsStdout bool,
|
|
) (string, error) {
|
|
var buffer bytes.Buffer
|
|
|
|
buffer.WriteString("{")
|
|
|
|
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
|
|
// Write the key which is necessarily string-valued in Miller, and in
|
|
// JSON for that matter :)
|
|
encoded := string(millerJSONEncodeString(pe.Key))
|
|
buffer.WriteString(colorizer.MaybeColorizeKey(encoded, outputIsStdout))
|
|
buffer.WriteString(": ")
|
|
|
|
// Write the value which is a mlrval
|
|
valueString, err := pe.Value.marshalJSONAux(jsonFormatting, elementNestingDepth+1, outputIsStdout)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
_, err = buffer.WriteString(valueString)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if pe.Next != nil {
|
|
buffer.WriteString(", ")
|
|
}
|
|
}
|
|
|
|
buffer.WriteString("}")
|
|
|
|
return buffer.String(), nil
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// JSON-stringifies a single field of a record
|
|
func (entry *MlrmapEntry) JSONStringifyInPlace(
|
|
jsonFormatting TJSONFormatting,
|
|
) {
|
|
outputBytes, err := entry.Value.MarshalJSON(jsonFormatting, false)
|
|
if err != nil {
|
|
entry.Value = FromError(err)
|
|
} else {
|
|
entry.Value = FromString(string(outputBytes))
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// JSON-parses a single field of a record
|
|
func (entry *MlrmapEntry) JSONParseInPlace() {
|
|
input := entry.Value.String()
|
|
err := entry.Value.UnmarshalJSON([]byte(input))
|
|
if err != nil {
|
|
entry.Value = FromError(err)
|
|
}
|
|
}
|
|
|
|
func (entry *MlrmapEntry) JSONTryParseInPlace() {
|
|
input := entry.Value.String()
|
|
pmv, err := TryUnmarshalJSON([]byte(input))
|
|
if err == nil {
|
|
entry.Value = pmv
|
|
}
|
|
}
|
|
|
|
// StringifyValuesRecursively is nominally for the `--jvquoteall` flag.
|
|
func (mlrmap *Mlrmap) StringifyValuesRecursively() {
|
|
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
|
|
pe.Value.StringifyValuesRecursively()
|
|
}
|
|
}
|