mirror of https://github.com/databricks/cli.git
91 lines
2.1 KiB
Go
91 lines
2.1 KiB
Go
package jsonloader
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/databricks/cli/libs/dyn"
|
|
)
|
|
|
|
func LoadJSON(data []byte) (dyn.Value, error) {
|
|
offsets := BuildLineOffsets(data)
|
|
reader := bytes.NewReader(data)
|
|
decoder := json.NewDecoder(reader)
|
|
|
|
// Start decoding from the top-level value
|
|
value, err := decodeValue(decoder, offsets)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
err = fmt.Errorf("unexpected end of JSON input")
|
|
}
|
|
return dyn.InvalidValue, err
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
func decodeValue(decoder *json.Decoder, offsets []LineOffset) (dyn.Value, error) {
|
|
// Read the next JSON token
|
|
token, err := decoder.Token()
|
|
if err != nil {
|
|
return dyn.InvalidValue, err
|
|
}
|
|
|
|
// Get the current byte offset
|
|
offset := decoder.InputOffset()
|
|
location := GetPosition(offset, offsets)
|
|
|
|
switch tok := token.(type) {
|
|
case json.Delim:
|
|
if tok == '{' {
|
|
// Decode JSON object
|
|
obj := make(map[string]dyn.Value)
|
|
for decoder.More() {
|
|
// Decode the key
|
|
keyToken, err := decoder.Token()
|
|
if err != nil {
|
|
return dyn.InvalidValue, err
|
|
}
|
|
key, ok := keyToken.(string)
|
|
if !ok {
|
|
return dyn.InvalidValue, fmt.Errorf("expected string for object key")
|
|
}
|
|
|
|
// Decode the value recursively
|
|
val, err := decodeValue(decoder, offsets)
|
|
if err != nil {
|
|
return dyn.InvalidValue, err
|
|
}
|
|
|
|
obj[key] = val
|
|
}
|
|
// Consume the closing '}'
|
|
if _, err := decoder.Token(); err != nil {
|
|
return dyn.InvalidValue, err
|
|
}
|
|
return dyn.NewValue(obj, []dyn.Location{location}), nil
|
|
} else if tok == '[' {
|
|
// Decode JSON array
|
|
var arr []dyn.Value
|
|
for decoder.More() {
|
|
val, err := decodeValue(decoder, offsets)
|
|
if err != nil {
|
|
return dyn.InvalidValue, err
|
|
}
|
|
arr = append(arr, val)
|
|
}
|
|
// Consume the closing ']'
|
|
if _, err := decoder.Token(); err != nil {
|
|
return dyn.InvalidValue, err
|
|
}
|
|
return dyn.NewValue(arr, []dyn.Location{location}), nil
|
|
}
|
|
default:
|
|
// Primitive types: string, number, bool, or null
|
|
return dyn.NewValue(tok, []dyn.Location{location}), nil
|
|
}
|
|
|
|
return dyn.InvalidValue, fmt.Errorf("unexpected token: %v", token)
|
|
}
|