-
Notifications
You must be signed in to change notification settings - Fork 1
/
json.go
133 lines (116 loc) · 4.08 KB
/
json.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Package json defines utilities for converting Starlark values to/from JSON strings based on go.starlark.net/lib/json.
package json
import (
"bytes"
"encoding/json"
"sync"
itn "github.com/1set/starlet/dataconv"
stdjson "go.starlark.net/lib/json"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
)
// ModuleName defines the expected name for this Module when used
// in starlark's load() function, eg: load('json', 'encode')
const ModuleName = "json"
var (
none = starlark.None
once sync.Once
jsonModule starlark.StringDict
)
// LoadModule loads the json module. It is concurrency-safe and idempotent.
func LoadModule() (starlark.StringDict, error) {
once.Do(func() {
mod := starlarkstruct.Module{
Name: ModuleName,
Members: starlark.StringDict{
"dumps": starlark.NewBuiltin(ModuleName+".dumps", dumps),
"try_dumps": starlark.NewBuiltin(ModuleName+".try_dumps", tryDumps),
"try_encode": starlark.NewBuiltin(ModuleName+".try_encode", tryEncode),
"try_decode": starlark.NewBuiltin(ModuleName+".try_decode", tryDecode),
"try_indent": starlark.NewBuiltin(ModuleName+".try_indent", tryIndent),
},
}
for k, v := range stdjson.Module.Members {
mod.Members[k] = v
}
jsonModule = starlark.StringDict{
ModuleName: &mod,
}
})
return jsonModule, nil
}
func dumps(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var (
obj starlark.Value
indent = starlark.MakeInt(0)
)
if err := starlark.UnpackArgs(fn.Name(), args, kwargs, "obj", &obj, "indent?", &indent); err != nil {
return none, err
}
// use 0 as default indent if failed to unpack indent
it, ok := indent.Int64()
if !ok || it < 0 {
it = 0
}
// use internal marshaler to support starlark types
data, err := itn.MarshalStarlarkJSON(obj, int(it))
if err != nil {
return none, err
}
return starlark.String(data), nil
}
func tryDumps(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var (
obj starlark.Value
indent = starlark.MakeInt(0)
)
if err := starlark.UnpackArgs(fn.Name(), args, kwargs, "obj", &obj, "indent?", &indent); err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
it, ok := indent.Int64()
if !ok || it < 0 {
it = 0
}
data, err := itn.MarshalStarlarkJSON(obj, int(it))
if err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
return starlark.Tuple{starlark.String(data), none}, nil
}
func tryEncode(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var x starlark.Value
if err := starlark.UnpackPositionalArgs(fn.Name(), args, kwargs, 1, &x); err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
encoded, err := itn.EncodeStarlarkJSON(x)
if err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
return starlark.Tuple{starlark.String(encoded), none}, nil
}
func tryDecode(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var s string
if err := starlark.UnpackArgs(fn.Name(), args, kwargs, "x", &s); err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
decoded, err := itn.DecodeStarlarkJSON([]byte(s))
if err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
return starlark.Tuple{decoded, none}, nil
}
func tryIndent(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var (
str string
prefix string
indent string
)
if err := starlark.UnpackArgs(fn.Name(), args, kwargs, "str", &str, "prefix?", &prefix, "indent?", &indent); err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
buf := new(bytes.Buffer)
if err := json.Indent(buf, []byte(str), prefix, indent); err != nil {
return starlark.Tuple{none, starlark.String(err.Error())}, nil
}
return starlark.Tuple{starlark.String(buf.String()), none}, nil
}