76 lines
1.9 KiB
Go
76 lines
1.9 KiB
Go
package definition
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
|
||
"git.yuntuo.hk/k2safe/orbit/internal/jsonvalue"
|
||
)
|
||
|
||
// ValidateData 在实例输入、任务成功结果、信号和块输出边界复用同一类型契约。
|
||
// 使用精确JSON数值文本;大小、重复字段、Unicode和嵌套限制先于类型检查。
|
||
func ValidateData(schema Type, raw json.RawMessage) error {
|
||
if err := checkType(schema, 0); err != nil {
|
||
return err
|
||
}
|
||
if len(raw) == 0 || len(raw) > 256<<10 {
|
||
return invalid("data", "JSON value required, maximum 256 KiB")
|
||
}
|
||
if _, err := jsonvalue.Canonical(raw); err != nil {
|
||
return invalid("data", "invalid JSON, duplicate fields or unsupported value limits")
|
||
}
|
||
var value any
|
||
d := json.NewDecoder(bytes.NewReader(raw))
|
||
d.UseNumber()
|
||
if err := d.Decode(&value); err != nil {
|
||
return invalid("data", "invalid JSON value")
|
||
}
|
||
return matchData(schema, value)
|
||
}
|
||
func matchData(schema Type, value any) error {
|
||
valid := false
|
||
switch schema.Kind {
|
||
case "JSON":
|
||
return nil
|
||
case "NULL":
|
||
valid = value == nil
|
||
case "STRING":
|
||
v, ok := value.(string)
|
||
valid = ok && (len(schema.Enum) == 0 || contains(schema.Enum, v))
|
||
case "NUMBER":
|
||
_, valid = value.(json.Number)
|
||
case "BOOLEAN":
|
||
_, valid = value.(bool)
|
||
case "OBJECT":
|
||
v, ok := value.(map[string]any)
|
||
if !ok || len(v) != len(schema.Fields) {
|
||
return invalid("data", "object fields do not match declared type")
|
||
}
|
||
for key, t := range schema.Fields {
|
||
child, ok := v[key]
|
||
if !ok {
|
||
return invalid("data", "required object field missing")
|
||
}
|
||
if err := matchData(t, child); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
case "ARRAY":
|
||
v, ok := value.([]any)
|
||
if !ok || len(v) > 4096 {
|
||
return invalid("data", "array required, maximum 4096 elements")
|
||
}
|
||
for _, child := range v {
|
||
if err := matchData(*schema.Items, child); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
if !valid {
|
||
return invalid("data", "value does not match declared type")
|
||
}
|
||
return nil
|
||
}
|