Documentation
¶
Overview ¶
Package strictjson decodes JSON so that what a reader sees in the text is exactly what the decoded value holds. encoding/json accepts a duplicate key and keeps the last value, matches keys case-insensitively, ignores unknown fields, and rewrites invalid UTF-8 and escaped lone surrogates to U+FFFD; each lets one text mean a value other than the one it shows. The checks here reject all of them, token by token against the target type, before encoding/json decodes.
The audit package reads proof artifacts with it (audit.UnmarshalStrict) and the agent package reads tool arguments and typed answers with it, which also requires every field schema.For lists as required.
Index ¶
- Constants
- Variables
- func BoundedError(err error) error
- func BoundedErrorN(err error, max int) error
- func Check(data []byte, t reflect.Type, opts *Options) error
- func CheckValue(raw []byte, t reflect.Type, at string, opts *Options) error
- func ExactFields(t reflect.Type) map[string]Field
- func Quote(s string) string
- func SchemaFields(t reflect.Type) map[string]Field
- func Unmarshal(data []byte, v any, opts *Options) error
- type Field
- type Options
Constants ¶
const MaxDepth = 128
MaxDepth is the deepest nesting of arrays and objects the structure of a document may have. The deepest document bide reads from its fixtures, examples, golden exports and test data nests 5 levels (the journal records in agent/testdata), and the deepest any test reads is 7; 128 leaves an order of magnitude of headroom, and is the nesting past which a document is an attack, not data. JSON kept verbatim (json.RawMessage, as a journal keeps a tool call's input and a tool's result, whatever a model or a tool made it) is not structure bide defines, so it is held to MaxVerbatimDepth instead: a record carrying a deep tool input must stay readable.
const MaxVerbatimDepth = 10000
MaxVerbatimDepth is the deepest nesting any document may have, structure and verbatim JSON together: about 10000, encoding/json's own limit (a verbatim value inside a journal record counts the record's own wrapper, so 9991 levels of one are read and 10000 are not). Check refuses a deeper document before any decoder runs, so no reader spends time or memory on it.
Variables ¶
var ErrTrailingData = errors.New("trailing data after the value")
ErrTrailingData reports data after the one JSON value.
Functions ¶
func BoundedError ¶ added in v0.22.0
BoundedError is err with its text cut to maxMessage characters (and Go-escaped where it is cut), keeping err for errors.Is and errors.As. nil and short errors come back as they are.
func BoundedErrorN ¶ added in v0.22.0
BoundedErrorN is BoundedError with a limit of max characters.
func Check ¶
Check consumes the one JSON value in data, checking it against t, and returns ErrTrailingData if anything but whitespace follows. An object decoded into a struct may use only that struct's exact JSON field names, each at most once, and must include each required one, with a value other than null unless the field takes null (Field.NullOK); every other object (a map, raw JSON, a type with its own UnmarshalJSON, an interface) is checked for duplicate names only, at any depth. Strings decoded into Go must have one spelling: no escaped lone surrogate, and in a []byte, base64 that is the standard encoding of its bytes. JSON kept verbatim (json.RawMessage) is checked for duplicate names only.
func CheckValue ¶
CheckValue checks the first JSON value in raw against t, as Check does, naming path in its errors. It does not look past that value.
func ExactFields ¶
ExactFields returns the exact JSON names encoding/json decodes into struct type t, with each field's type, by encoding/json's own rules: exported fields by tag name or Go name (a "-" tag is skipped), and the fields of an untagged embedded struct promoted into t. When several fields claim one name, the shallowest wins, and at equal depth a tagged field wins over an untagged one. A name still claimed by several fields is one encoding/json ignores; it is kept here, and the decode that follows (DisallowUnknownFields) rejects it. No field is required, and every field takes null.
func Quote ¶ added in v0.22.0
Quote is s as Go quotes it (so a control character or an escape sequence is written out, not sent to a terminal), cut to maxQuoted characters with "..." when longer. Errors name text from the document through it, never raw.
func SchemaFields ¶
SchemaFields returns the names struct type t accepts as schema.For describes them: the fields encoding/json reads (jsonfields.Of), each required exactly when the schema lists it as required. A required field takes null only when its schema admits any value (For leaves an interface, json.RawMessage, or a json.Unmarshaler other than time.Time unconstrained); otherwise encoding/json would read null as the zero value, one the document never gave. An optional field takes null (OpenAI strict mode sends it). A type jsonfields cannot resolve accepts no names.
Types ¶
type Field ¶
Field is one name a struct accepts: the type its value decodes into, whether a document must include it, and whether it may be null.
type Options ¶
type Options struct {
// Fields returns the names struct type t accepts, each exactly as spelled. Nil means
// ExactFields.
Fields func(t reflect.Type) map[string]Field
// Shapes maps a type to the type its JSON is checked against instead: for a type whose own
// UnmarshalJSON matches names loosely, its wire shape.
Shapes map[reflect.Type]reflect.Type
// Hooks maps a type to a check of its own: the value is consumed (checked for duplicate
// names only) and its raw text, with the path to it, is handed to the hook.
Hooks map[reflect.Type]func(raw []byte, path string) error
// AllowUnknown lets an object decoded into a struct carry names the struct does not have, as a
// document written by a later version does. Such a name must not be a case variant of a name
// the struct has ("Kind" beside a "kind" field), which encoding/json would read into that
// field; its value is checked like any value decoded into Go: no duplicate names at any depth
// and no escaped lone surrogate.
AllowUnknown bool
}
Options configure a check.