Documentation
¶
Overview ¶
Package schemaexec provides symbolic execution of jq queries over JSON schemas.
Index ¶
- func AddSchemasForTest(lhs, rhs *oas3.Schema, opts SchemaExecOptions) *oas3.Schema
- func ArrayType(items *oas3.Schema) *oas3.Schema
- func BoolType() *oas3.Schema
- func Bottom() *oas3.Schema
- func BuildArray(items *oas3.Schema, elements []*oas3.Schema) *oas3.Schema
- func BuildObject(props map[string]*oas3.Schema, required []string) *oas3.Schema
- func ConstBool(b bool) *oas3.Schema
- func ConstInteger(n int64) *oas3.Schema
- func ConstNull() *oas3.Schema
- func ConstNumber(n float64) *oas3.Schema
- func ConstString(s string) *oas3.Schema
- func FingerprintSchema(s *oas3.Schema) string
- func GetProperty(obj *oas3.Schema, key string, opts SchemaExecOptions) *oas3.Schema
- func HasProperty(obj *oas3.Schema, key string, opts SchemaExecOptions) *oas3.Schema
- func IntegerType() *oas3.Schema
- func Intersect(a, b *oas3.Schema, opts SchemaExecOptions) *oas3.Schema
- func MergeObjects(a, b *oas3.Schema, opts SchemaExecOptions) *oas3.Schema
- func MightBeArray(s *oas3.Schema) bool
- func MightBeNumber(s *oas3.Schema) bool
- func MightBeObject(s *oas3.Schema) bool
- func MightBeString(s *oas3.Schema) bool
- func NullType() *oas3.Schema
- func NumberType() *oas3.Schema
- func ObjectType() *oas3.Schema
- func OpenObjectType(values *oas3.Schema) *oas3.Schema
- func RequireType(s *oas3.Schema, typ oas3.SchemaType, opts SchemaExecOptions) *oas3.Schema
- func StringType() *oas3.Schema
- func Top() *oas3.Schema
- func Union(schemas []*oas3.Schema, opts SchemaExecOptions) *oas3.Schema
- type AValue
- type AllocOrigin
- type Analysis
- type ArrayCardinality
- type Closure
- type DSU
- type Fingerprinter
- type LogLevel
- type Logger
- type MergeMode
- type PathAllElements
- type PathSegment
- type PathWildcard
- type SValue
- type SchemaExecOptions
- type SchemaExecResult
- type SchemaLogOptions
- type SchemaSemantics
- type ValueKind
- type Verdict
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddSchemasForTest ¶ added in v0.13.0
func AddSchemasForTest(lhs, rhs *oas3.Schema, opts SchemaExecOptions) *oas3.Schema
AddSchemasForTest exposes "+" semantics for tests without requiring a VM env.
func Bottom ¶
Bottom returns a schema that matches nothing (the "never" type). By convention, we use nil to represent Bottom/Never.
func BuildArray ¶
BuildArray creates an array schema from element schemas.
func BuildObject ¶
BuildObject creates an object schema from property map. Simplified version for Phase 1.
func ConstInteger ¶
ConstInteger creates a schema for a specific integer.
func ConstNumber ¶
ConstNumber creates a schema for a specific number.
func ConstString ¶
ConstString creates a schema for a specific string literal.
func FingerprintSchema ¶ added in v0.13.0
FingerprintSchema is a convenience function using the default fingerprinter
func GetProperty ¶
GetProperty extracts the schema for a property from an object schema. Simplified version for Phase 1.
func HasProperty ¶
HasProperty refines an object schema to require a property exists. Used for guards like: select(has("foo"))
func IntegerType ¶
IntegerType creates a basic integer schema (unconstrained).
func Intersect ¶
func Intersect(a, b *oas3.Schema, opts SchemaExecOptions) *oas3.Schema
Intersect creates a schema that matches all input schemas (allOf). This is used for narrowing and constraint combination.
func MergeObjects ¶
func MergeObjects(a, b *oas3.Schema, opts SchemaExecOptions) *oas3.Schema
MergeObjects combines two object schemas (for the + operator on objects).
func MightBeArray ¶
MightBeArray checks if schema could be an array.
func MightBeNumber ¶
MightBeNumber checks if schema could be a number.
func MightBeObject ¶
MightBeObject checks if schema could be an object.
func MightBeString ¶
MightBeString checks if schema could be a string.
func NumberType ¶
NumberType creates a basic number schema (unconstrained).
func ObjectType ¶
ObjectType creates an object schema with no declared members.
func OpenObjectType ¶ added in v0.13.0
OpenObjectType creates an object schema that admits undeclared members.
func RequireType ¶
func RequireType(s *oas3.Schema, typ oas3.SchemaType, opts SchemaExecOptions) *oas3.Schema
RequireType narrows a schema to a specific type. Used for type guards like: select(type == "array")
func StringType ¶
StringType creates a basic string schema (unconstrained).
Types ¶
type AValue ¶
AValue is the abstract value stored on the symbolic VM stack. Phase 1a: only VSchema is used by the existing code. VClosure will be used in Phase 1b+.
func NewClosureValue ¶
func NewSchemaValue ¶
NewSchemaValue constructs an AValue containing a Schema.
type AllocOrigin ¶ added in v0.13.0
type AllocOrigin struct {
PC int // Program counter where allocation occurred
Context string // Semantic context (e.g., "reduce_accumulator", "map_accumulator")
CallSite int // Return address of the enclosing call frame (-1 at top level)
}
AllocOrigin tracks where an allocID was created in the AST/execution
type Analysis ¶ added in v0.13.0
type Analysis struct {
// Output is the inferred output schema (usable as the projected response
// shape). Nil when the query provably produces no output (Bottom).
Output *oas3.Schema
// Verdict classifies the result; see the Verdict constants.
Verdict Verdict
// Causes holds human-readable explanations with schema locations for
// VerdictUnverifiable and VerdictProvenBroken, e.g.
// "property access on non-object type at $.anyOf[0]".
Causes []string
// Semantics records the schema interpretation mode the analysis ran
// under. Verdicts are only meaningful relative to it: under the default
// SchemaSemanticsSpeakeasy, "valid input" means a value as modeled by
// Speakeasy's generators (closed objects, implied types), NOT an
// arbitrary payload the wire could carry. Under SchemaSemanticsRaw a
// missing property is never provably broken without an explicit
// additionalProperties: false.
Semantics SchemaSemantics
}
Analysis is the result of Analyze: the inferred output schema plus a classification of how trustworthy that inference is.
func Analyze ¶ added in v0.13.0
func Analyze(ctx context.Context, q *gojq.Query, input *oas3.Schema, opts ...SchemaExecOptions) (*Analysis, error)
Analyze symbolically executes a jq query against an input schema and classifies the result.
Contract for consumers (e.g. generators linting authored jq projections against response schemas):
- VerdictProvenBroken is safe to fail a build on: the query provably produces null (or nothing) for every valid input.
- VerdictUnverifiable is NOT a failure — the library could not decide (open schemas, oneOf, unsupported operations legitimately widen to unknown). Consumers should warn at most.
- VerdictProven means the returned Output schema is a sound, fully concrete over-approximation of all possible outputs.
Analyze always runs in lenient mode (StrictMode is ignored): strict mode aborts on the first widening, whereas classification needs the completed output schema. The verdict is computed by deep-walking the output — including array items, object properties, and union branches — so a Top buried inside a container makes the result Unverifiable, not Proven.
jq missing-key semantics are respected: optional property access yields null UNIONED with the real types, which stays Proven. Only an output that is null for every input (or has no output at all) is ProvenBroken.
Verdicts are relative to opts.Semantics (echoed on Analysis.Semantics). Under the default SchemaSemanticsSpeakeasy, "valid input" means a value as modeled by Speakeasy's generators — objects are closed, so access to an undeclared property is provably null (typo detection). Under SchemaSemanticsRaw, objects without additionalProperties are open and such access is merely Unverifiable.
type ArrayCardinality ¶ added in v0.13.0
type ArrayCardinality struct {
MinItems *int // Lower bound: 0 = maybe-empty, 1+ = must-be-non-empty
MaxItems *int // Upper bound: nil = unbounded
}
ArrayCardinality tracks bounds on array size for lattice-based merging
func (*ArrayCardinality) Join ¶ added in v0.13.0
func (a *ArrayCardinality) Join(other *ArrayCardinality) *ArrayCardinality
Join performs lattice join (LUB) on two cardinality bounds This is the mathematically sound merge operation for the cardinality lattice
type Closure ¶
Closure abstracts a function value captured by pushpc. PC is the entry address, ScopeIndex is the captured lexical scope index.
type DSU ¶ added in v0.13.0
type DSU struct {
// contains filtered or unexported fields
}
DSU implements Disjoint Set Union (Union-Find) for allocID equivalence classes
type Fingerprinter ¶ added in v0.13.0
type Fingerprinter struct {
// contains filtered or unexported fields
}
Fingerprinter provides schema canonicalization and hashing with caching
func NewFingerprinter ¶ added in v0.13.0
func NewFingerprinter() *Fingerprinter
NewFingerprinter creates a new fingerprinter
func (*Fingerprinter) FingerprintSchema ¶ added in v0.13.0
func (fp *Fingerprinter) FingerprintSchema(s *oas3.Schema) string
FingerprintSchema returns a deterministic hex fingerprint for a schema Uses persistent caching for performance
func (*Fingerprinter) FingerprintSchemaWithExclusions ¶ added in v0.13.0
func (fp *Fingerprinter) FingerprintSchemaWithExclusions(s *oas3.Schema, excl map[*oas3.Schema]struct{}) string
FingerprintSchemaWithExclusions computes fingerprint but skips persistent cache for schemas in the exclusion set (used for mutable schemas)
func (*Fingerprinter) Reset ¶ added in v0.13.0
func (fp *Fingerprinter) Reset()
Reset clears the persistent cache
type LogLevel ¶
type LogLevel int
LogLevel represents the severity level for logs.
func ParseLogLevel ¶
ParseLogLevel parses a string into a LogLevel.
type Logger ¶
type Logger interface {
// Debugf, Infof, Warnf, Errorf log formatted messages at respective levels.
Debugf(format string, args ...any)
Infof(format string, args ...any)
Warnf(format string, args ...any)
Errorf(format string, args ...any)
// With returns a child logger augmented with the provided fields.
With(fields map[string]any) Logger
}
Logger is the interface used by the executor for logging.
type MergeMode ¶ added in v0.13.0
type MergeMode int
MergeMode determines how schemas are merged
const ( // MergeConjunctive represents allOf semantics (intersection) // - Properties: union of keys, recursively merge overlapping // - Required: union (field required in ANY subschema) // - Types: intersection (must be compatible) MergeConjunctive MergeMode = iota // MergeDisjunctive represents anyOf semantics (union/LUB) // - Properties: union of keys, union overlapping property schemas // - Required: intersection (field required in ALL subschemas) // - Types: union (more permissive) MergeDisjunctive )
type PathAllElements ¶ added in v0.13.0
type PathAllElements struct{}
PathAllElements represents every array index selected by .[] in path mode.
type PathSegment ¶
type PathSegment struct {
Key interface{} // string, int, PathWildcard, or PathAllElements
IsSymbolic bool // True for unknown-index and all-elements segments
}
PathSegment represents one segment of a path expression
type PathWildcard ¶
type PathWildcard struct{}
PathWildcard represents an unknown single array index or slice path.
type SValue ¶
SValue wraps a schema for the schema VM stack. This is the value type that flows through the schema virtual machine.
type SchemaExecOptions ¶
type SchemaExecOptions struct {
// Semantics selects the schema interpretation mode (see SchemaSemantics).
// The zero value is SchemaSemanticsSpeakeasy.
Semantics SchemaSemantics
// Limits to prevent combinatorial explosion
AnyOfLimit int // Max branches in anyOf before widening (default: 10)
EnumLimit int // Max enum values before widening to plain type (default: 50)
MaxDepth int // Max recursion depth (default: 100)
// Behavior flags
StrictMode bool // If true, fail on unsupported ops; if false, widen to Top (default: false)
EnableWarnings bool // If true, collect precision-loss warnings (default: true)
EnableMemo bool // If true, enable memoization for performance (default: true)
// Widening level controls how aggressively we simplify schemas
// 0 = none (keep all precision)
// 1 = conservative (keep types, drop facets when limits exceeded)
// 2 = aggressive (collapse to Top when limits exceeded)
WideningLevel int // default: 1
// Logging configuration
LogLevel string // Log level: "", "error", "warn", "info", "debug". Default "": no output — the library is silent on stdout/stderr unless a level is set.
LogMaxEnumValues int // Max enum values to show in logs (default: 5)
LogMaxProps int // Max object properties to show in logs (default: 5)
LogStackPreviewDepth int // Max stack depth to preview in logs (default: 3)
LogSchemaDeltas bool // If true, include schema deltas in debug logs (default: true)
// contains filtered or unexported fields
}
SchemaExecOptions configures symbolic execution behavior. Callers should start from DefaultOptions when changing individual fields. Public entry points fill zero-valued numeric limits from DefaultOptions, but boolean fields whose defaults are true (EnableWarnings, EnableMemo, and LogSchemaDeltas) remain false in a zero-value struct.
func DefaultOptions ¶
func DefaultOptions() SchemaExecOptions
DefaultOptions returns the default configuration for schema execution.
type SchemaExecResult ¶
type SchemaExecResult struct {
Schema *oas3.Schema // The resulting schema after transformation
Warnings []string // Warnings about precision loss or unsupported operations
}
SchemaExecResult contains the output schema and diagnostic information.
func ExecSchema ¶
func ExecSchema(ctx context.Context, code *gojq.Code, input *oas3.Schema, opts SchemaExecOptions) (*SchemaExecResult, error)
ExecSchema executes compiled jq bytecode symbolically on an input schema. This is the core execution function - Phase 2 implementation.
func RunSchema ¶
func RunSchema(ctx context.Context, query *gojq.Query, input *oas3.Schema, opts ...SchemaExecOptions) (*SchemaExecResult, error)
RunSchema executes a jq query symbolically on an input JSON Schema. It parses and compiles the query, then performs symbolic execution to compute the output schema.
Example:
query, _ := gojq.Parse(".foo.bar")
inputSchema := &oas3.Schema{...}
result, err := schemaexec.RunSchema(context.Background(), query, inputSchema)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Output schema: %+v\n", result.Schema)
func (*SchemaExecResult) String ¶
func (r *SchemaExecResult) String() string
String returns a string representation of the result for debugging.
type SchemaLogOptions ¶
type SchemaLogOptions struct {
LogMaxEnumValues int // default 5
LogMaxProps int // default 5
LogMaxAnyOfBranches int // default 5
LogStackPreviewDepth int // default 3 (not used here, but kept for parity)
}
SchemaLogOptions control verbosity for schema summaries/deltas.
type SchemaSemantics ¶ added in v0.13.0
type SchemaSemantics int
SchemaSemantics selects how the executor interprets schemas that do not fully specify their shape.
const ( // SchemaSemanticsSpeakeasy (the default) targets Speakeasy-processed // OpenAPI documents and mirrors the structural inference Speakeasy's // SDK/CLI generators apply: // - untyped schemas get an implied type from structure (enum→string, // const→its scalar type, properties/additionalProperties→object, // items→array); // - an object property that is not declared and has no // additionalProperties is treated as ABSENT (closed world): access // yields null. "Valid input" means a value as modeled by the // generator, not an arbitrary API payload. SchemaSemanticsSpeakeasy SchemaSemantics = iota // SchemaSemanticsRaw keeps raw JSON Schema semantics at navigation: // - untyped schemas are NOT implied to a single type when dispatching // property access/iteration; they conservatively widen to Top; // - an object property that is not declared and has no // additionalProperties is treated as OPEN (additionalProperties // defaults to true in JSON Schema): access yields unknown ∪ null, // so nothing is ever "provably missing" without an explicit // additionalProperties: false. // Builtins conservatively widen when an operand has only an implied type, // because raw JSON Schema still permits values of every other JSON type. SchemaSemanticsRaw )
type Verdict ¶ added in v0.13.0
type Verdict int
Verdict classifies the outcome of symbolically executing a jq query against an input schema. The zero value is VerdictUnverifiable. The library is best-effort: it cannot prove everything, but when it CAN prove a query is broken, consumers may hard-error.
const ( // VerdictUnverifiable: the output contains Top (unknown) somewhere — the // library could not decide. This is NOT an error; consumers should warn // at most. VerdictUnverifiable Verdict = iota // VerdictProven: a concrete output schema was inferred; it contains no // Top (unknown) anywhere and is not provably empty. Safe to use as the // projected output shape. VerdictProven // VerdictProvenBroken: the output is provably null or empty for EVERY // valid input — e.g. a typo'd leaf yielding const null, or a query whose // execution paths are all dead (Bottom). Safe to fail a build on. VerdictProvenBroken )