2020-06-08 03:29:51 +03:00
|
|
|
package json
|
|
|
|
|
|
|
|
import (
|
2022-06-01 17:55:55 +03:00
|
|
|
"bytes"
|
|
|
|
"embed"
|
2020-06-08 03:29:51 +03:00
|
|
|
stdjson "encoding/json"
|
2022-06-01 17:55:55 +03:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"math/big"
|
2021-08-17 13:06:32 +03:00
|
|
|
|
|
|
|
"github.com/wader/fq/format"
|
2022-06-01 17:55:55 +03:00
|
|
|
"github.com/wader/fq/internal/colorjson"
|
2022-01-24 23:21:48 +03:00
|
|
|
"github.com/wader/fq/pkg/bitio"
|
2021-08-17 13:06:32 +03:00
|
|
|
"github.com/wader/fq/pkg/decode"
|
2022-07-16 19:39:57 +03:00
|
|
|
"github.com/wader/fq/pkg/interp"
|
2021-12-02 00:48:25 +03:00
|
|
|
"github.com/wader/fq/pkg/scalar"
|
2022-06-01 17:55:55 +03:00
|
|
|
"github.com/wader/gojq"
|
2020-06-08 03:29:51 +03:00
|
|
|
)
|
|
|
|
|
2022-06-01 17:55:55 +03:00
|
|
|
//go:embed json.jq
|
|
|
|
var jsonFS embed.FS
|
2021-11-24 17:25:27 +03:00
|
|
|
|
2020-06-08 03:29:51 +03:00
|
|
|
func init() {
|
2022-07-16 19:39:57 +03:00
|
|
|
interp.RegisterFormat(decode.Format{
|
2020-06-08 03:29:51 +03:00
|
|
|
Name: format.JSON,
|
2022-06-01 17:55:55 +03:00
|
|
|
Description: "JavaScript Object Notation",
|
|
|
|
ProbeOrder: format.ProbeOrderText,
|
2020-06-08 03:29:51 +03:00
|
|
|
Groups: []string{format.PROBE},
|
|
|
|
DecodeFn: decodeJSON,
|
2022-06-01 17:55:55 +03:00
|
|
|
Functions: []string{"_todisplay"},
|
2020-06-08 03:29:51 +03:00
|
|
|
})
|
2022-07-27 14:20:48 +03:00
|
|
|
interp.RegisterFS(jsonFS)
|
2022-06-01 17:55:55 +03:00
|
|
|
interp.RegisterFunc1("_tojson", toJSON)
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
2022-07-19 19:33:50 +03:00
|
|
|
func decodeJSON(d *decode.D, _ any) any {
|
2022-01-24 23:21:48 +03:00
|
|
|
br := d.RawLen(d.Len())
|
2022-06-01 17:55:55 +03:00
|
|
|
|
|
|
|
// keep in sync with gojq fromJSON
|
2022-01-24 23:21:48 +03:00
|
|
|
jd := stdjson.NewDecoder(bitio.NewIOReader(br))
|
2022-06-01 17:55:55 +03:00
|
|
|
jd.UseNumber()
|
2021-12-02 00:48:25 +03:00
|
|
|
var s scalar.S
|
2021-11-03 19:19:33 +03:00
|
|
|
if err := jd.Decode(&s.Actual); err != nil {
|
2021-11-17 18:26:13 +03:00
|
|
|
d.Fatalf(err.Error())
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
2022-06-01 17:55:55 +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
|
|
|
}
|
2021-11-24 17:25:27 +03:00
|
|
|
|
2022-06-01 17:55:55 +03:00
|
|
|
s.Actual = gojq.NormalizeNumbers(s.Actual)
|
2021-12-03 02:06:11 +03:00
|
|
|
d.Value.V = &s
|
2021-11-24 17:25:27 +03:00
|
|
|
d.Value.Range.Len = d.Len()
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2022-06-01 17:55:55 +03:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|