1
1
mirror of https://github.com/wader/fq.git synced 2024-11-28 03:02:55 +03:00
fq/format/json/json.go

86 lines
1.7 KiB
Go
Raw Normal View History

2020-06-08 03:29:51 +03:00
package json
import (
"bytes"
"embed"
2020-06-08 03:29:51 +03:00
stdjson "encoding/json"
"errors"
"fmt"
"io"
"math/big"
"github.com/wader/fq/format"
"github.com/wader/fq/internal/colorjson"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
"github.com/wader/gojq"
2020-06-08 03:29:51 +03:00
)
//go:embed json.jq
var jsonFS embed.FS
2020-06-08 03:29:51 +03:00
func init() {
interp.RegisterFormat(decode.Format{
2020-06-08 03:29:51 +03:00
Name: format.JSON,
Description: "JavaScript Object Notation",
ProbeOrder: format.ProbeOrderText,
2020-06-08 03:29:51 +03:00
Groups: []string{format.PROBE},
DecodeFn: decodeJSON,
Functions: []string{"_todisplay"},
2020-06-08 03:29:51 +03:00
})
interp.RegisterFS(jsonFS)
interp.RegisterFunc1("_tojson", toJSON)
2020-06-08 03:29:51 +03:00
}
func decodeJSON(d *decode.D, _ any) any {
br := d.RawLen(d.Len())
// keep in sync with gojq fromJSON
jd := stdjson.NewDecoder(bitio.NewIOReader(br))
jd.UseNumber()
var s scalar.S
if err := jd.Decode(&s.Actual); err != nil {
d.Fatalf(err.Error())
2020-06-08 03:29:51 +03:00
}
if err := jd.Decode(new(any)); !errors.Is(err, io.EOF) {
d.Fatalf("trialing data after top-level value")
2020-06-08 03:29:51 +03:00
}
s.Actual = gojq.NormalizeNumbers(s.Actual)
d.Value.V = &s
d.Value.Range.Len = d.Len()
2020-06-08 03:29:51 +03:00
return nil
}
type ToJSONOpts struct {
Indent int
}
func toJSON(_ *interp.Interp, c any, opts ToJSONOpts) any {
// TODO: share
cj := colorjson.NewEncoder(
false,
false,
opts.Indent,
func(v any) any {
switch v := v.(type) {
case gojq.JQValue:
return v.JQValueToGoJQ()
case nil, bool, float64, int, string, *big.Int, map[string]any, []any:
return v
default:
panic(fmt.Sprintf("toValue not a JQValue value: %#v %T", v, v))
}
},
colorjson.Colors{},
)
bb := &bytes.Buffer{}
if err := cj.Marshal(c, bb); err != nil {
return err
}
return bb.String()
}