/
json.go
137 lines (123 loc) · 3.11 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
134
135
136
137
package core
import (
"encoding/json"
"errors"
"fmt"
"log"
"strings"
jsoniter "github.com/inoxlang/inox/internal/jsoniter"
"github.com/inoxlang/inox/internal/utils"
)
func ToJSON(ctx *Context, v Serializable, pattern *OptionalParam[Pattern]) String {
var patt Pattern
if pattern == nil {
patt = ANYVAL_PATTERN
} else {
patt = pattern.Value
}
return ToJSONWithConfig(ctx, v, JSONSerializationConfig{
ReprConfig: &ReprConfig{},
Pattern: patt,
Location: "/",
})
}
func ToJSONWithConfig(ctx *Context, v Serializable, config JSONSerializationConfig) String {
stream := jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0)
if err := v.WriteJSONRepresentation(ctx, stream, config, 0); err != nil {
panic(err)
}
if stream.Error != nil {
panic(stream.Error)
}
return String(stream.Buffer())
}
func ToPrettyJSON(ctx *Context, v Serializable, pattern *OptionalParam[Pattern]) String {
s := ToJSON(ctx, v, pattern)
var unmarshalled interface{}
err := json.Unmarshal([]byte(s), &unmarshalled)
if err != nil {
panic(errors.New("failed to serialize value to JSON"))
}
b, err := utils.MarshalIndentJsonNoHTMLEspace(unmarshalled, "", " ")
if err != nil {
panic(err)
}
return String(b)
}
func ToJSONVal(ctx *Context, v Serializable) interface{} {
s := ToJSON(ctx, v, nil)
var jsonVal interface{}
err := json.Unmarshal([]byte(s), &jsonVal)
if err != nil {
log.Panicln("from json:", err)
}
return jsonVal
}
func ConvertJSONValToInoxVal(v any, immutable bool) Serializable {
switch val := v.(type) {
case nil:
return Nil
case map[string]any:
if immutable {
valMap := ValMap{}
for key, value := range val {
valMap[key] = ConvertJSONValToInoxVal(value, immutable)
}
return NewRecordFromMap(valMap)
} else {
valMap := ValMap{}
for key, value := range val {
valMap[key] = ConvertJSONValToInoxVal(value, immutable)
}
return NewObjectFromMapNoInit(valMap)
}
case []any:
l := make([]Serializable, len(val))
for i, e := range val {
l[i] = ConvertJSONValToInoxVal(e, immutable)
}
if immutable {
return NewTuple(l)
}
return &List{underlyingList: &ValueList{elements: l}}
case int:
return Int(val)
case float64:
return Float(val)
case json.Number:
if strings.Contains(val.String(), ".") {
float, err := val.Float64()
if err != nil {
panic(fmt.Errorf("failed to parse float `%s`: %w", val.String(), err))
}
return Float(float)
}
integer, err := val.Int64()
if err != nil {
panic(fmt.Errorf("failed to parse integer `%s`: %w", val.String(), err))
}
return Int(integer)
case bool:
return Bool(val)
case string:
return String(val)
default:
panic(fmt.Errorf("cannot convert value of type %T to Inox Value", val))
}
}
func parseJson(ctx *Context, v any) (any, error) {
var b []byte
switch val := v.(type) {
case WrappedBytes:
b = val.UnderlyingBytes()
case WrappedString:
b = []byte(val.UnderlyingString())
default:
return "", fmt.Errorf("cannot parse non string|bytes: %T", val)
}
var result interface{}
if err := json.Unmarshal(b, &result); err != nil {
return nil, err
}
return ConvertJSONValToInoxVal(result, false), nil
}