2025-10-15 10:12:44 +03:00

166 lines
3.8 KiB
Go

package packagejson
import (
"fmt"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
"github.com/go-json-experiment/json"
"github.com/go-json-experiment/json/jsontext"
)
type JSONValueType int8
const (
JSONValueTypeNotPresent JSONValueType = iota
JSONValueTypeNull
JSONValueTypeString
JSONValueTypeNumber
JSONValueTypeBoolean
JSONValueTypeArray
JSONValueTypeObject
)
func (t JSONValueType) String() string {
switch t {
case JSONValueTypeNull:
return "null"
case JSONValueTypeString:
return "string"
case JSONValueTypeNumber:
return "number"
case JSONValueTypeBoolean:
return "boolean"
case JSONValueTypeArray:
return "array"
case JSONValueTypeObject:
return "object"
default:
return fmt.Sprintf("unknown(%d)", t)
}
}
type JSONValue struct {
Type JSONValueType
Value any
}
func (v *JSONValue) IsFalsy() bool {
switch v.Type {
case JSONValueTypeNotPresent, JSONValueTypeNull:
return true
case JSONValueTypeString:
return v.Value == ""
case JSONValueTypeNumber:
return v.Value == 0
case JSONValueTypeBoolean:
return !v.Value.(bool)
default:
return false
}
}
func (v JSONValue) AsObject() *collections.OrderedMap[string, JSONValue] {
if v.Type != JSONValueTypeObject {
panic(fmt.Sprintf("expected object, got %v", v.Type))
}
return v.Value.(*collections.OrderedMap[string, JSONValue])
}
func (v JSONValue) AsArray() []JSONValue {
if v.Type != JSONValueTypeArray {
panic(fmt.Sprintf("expected array, got %v", v.Type))
}
return v.Value.([]JSONValue)
}
var _ json.UnmarshalerFrom = (*JSONValue)(nil)
func (v *JSONValue) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
return unmarshalJSONValueV2[JSONValue](v, dec)
}
func unmarshalJSONValue[T any](v *JSONValue, data []byte) error {
if string(data) == "null" {
*v = JSONValue{Type: JSONValueTypeNull}
} else if data[0] == '"' {
v.Type = JSONValueTypeString
return json.Unmarshal(data, &v.Value)
} else if data[0] == '[' {
var elements []T
if err := json.Unmarshal(data, &elements); err != nil {
return err
}
v.Type = JSONValueTypeArray
v.Value = elements
} else if data[0] == '{' {
var object collections.OrderedMap[string, T]
if err := json.Unmarshal(data, &object); err != nil {
return err
}
v.Type = JSONValueTypeObject
v.Value = &object
} else if string(data) == "true" {
v.Type = JSONValueTypeBoolean
v.Value = true
} else if string(data) == "false" {
v.Type = JSONValueTypeBoolean
v.Value = false
} else {
v.Type = JSONValueTypeNumber
return json.Unmarshal(data, &v.Value)
}
return nil
}
func unmarshalJSONValueV2[T any](v *JSONValue, dec *jsontext.Decoder) error {
switch dec.PeekKind() {
case 'n': // jsontext.Null.Kind()
if _, err := dec.ReadToken(); err != nil {
return err
}
v.Value = nil
v.Type = JSONValueTypeNull
return nil
case '"':
v.Type = JSONValueTypeString
if err := json.UnmarshalDecode(dec, &v.Value); err != nil {
return err
}
case '[':
if _, err := dec.ReadToken(); err != nil {
return err
}
var elements []T
for dec.PeekKind() != jsontext.EndArray.Kind() {
var element T
if err := json.UnmarshalDecode(dec, &element); err != nil {
return err
}
elements = append(elements, element)
}
if _, err := dec.ReadToken(); err != nil {
return err
}
v.Type = JSONValueTypeArray
v.Value = elements
case '{':
var object collections.OrderedMap[string, T]
if err := json.UnmarshalDecode(dec, &object); err != nil {
return err
}
v.Type = JSONValueTypeObject
v.Value = &object
case 't', 'f': // jsontext.True.Kind(), jsontext.False.Kind()
v.Type = JSONValueTypeBoolean
if err := json.UnmarshalDecode(dec, &v.Value); err != nil {
return err
}
default:
v.Type = JSONValueTypeNumber
if err := json.UnmarshalDecode(dec, &v.Value); err != nil {
return err
}
}
return nil
}