jpath

package module
v0.0.0-...-6330766 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2026 License: MIT Imports: 11 Imported by: 0

README

jpath

Build Status Code Coverage Maintainability GitHub

jpath is a JSONPath parser/compiler for Go. It is built around a two-stage pipeline: parse into an inspectable AST, then compile into a composed function chain. That separation lets you validate or rewrite paths before execution, while keeping runtime evaluation fast and predictable. Extension functions are scoped through registries so custom behavior can be sandboxed.

Features

  • Parse JSONPath expressions into AST nodes
  • Compile AST into a fast runnable function chain
  • Register extension filter functions per registry instance
  • Keep registries isolated for sandboxed behavior
  • Run JSONPath compliance suite fixtures in tests

Core API

Signature Description
Parse(query string) (*PathExpr, error) Parse a query string into an AST (PathExpr)
MustParse(query string) *PathExpr Parse a query string into an AST and panic on error
Compile(path *PathExpr) (Path, error) Compile an AST into an executable Path function
MustCompile(path *PathExpr) Path Compile an AST into an executable Path function and panic on error
Query(query string, document any) ([]any, error) Parse, compile, and execute a query against a document with the default registry
MustQuery(query string, document any) []any Parse, compile, and execute a query against a document with the default registry, panicking on error
Path func(document any) []any Compiled query function returned by Compile
Parse, compile, and run
registry := jpath.NewRegistry()
pathExpr, err := registry.Parse("$.store.book[*].title")
if err != nil {
	panic(err)
}
path, err := registry.Compile(pathExpr)
if err != nil {
	panic(err)
}
matches := path(document)
One-step query
matches := jpath.MustQuery("$.store.book[*].title", document)

Registry Management

Signature Description
NewRegistry() *Registry Create an isolated registry preloaded with default JSONPath functions
.Parse(query string) (*PathExpr, error) Parse using this registry context
.Compile(path *PathExpr) (Path, error) Compile using this registry's function definitions
.Query(query string, document any) ([]any, error) Parse, compile, and execute using this registry
.RegisterFunction(name string, arity int, fn Function) error Register a scalar extension function with fixed arity
.RegisterDefinition(name string, def *FunctionDefinition) error Register a full custom function definition (validation + evaluation)
.Clone() *Registry Copy the registry so function registration can diverge safely

Top-level functions use a default registry. Use explicit Registry instances when you need sandboxed extension registration.

Register an extension function
registry := jpath.NewRegistry()
registry.MustRegisterFunction(
	"startsWith", 2, func(args ...any) (any, bool) {
		left, ok := args[0].(string)
		if !ok {
			return nil, false
		}
		right, ok := args[1].(string)
		if !ok {
			return nil, false
		}
		return strings.HasPrefix(left, right), true
	},
)

Use RegisterDefinition when you need full control over validation rules, node-list arguments, or custom result shapes

Status

  • Implements RFC 9535 (JSONPath)
  • Passes the JSONPath Compliance Test Suite
  • Pre-v1.0.0: API may change

Documentation

Overview

Package jpath implements JSONPath parsing, compilation, and execution

Queries compile to composed function chains The same compiled path can execute against different JSON documents

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidPath is raised when a JSONPath query cannot be parsed
	ErrInvalidPath = errors.New("invalid JSONPath query")

	// ErrExpectedRoot indicates the query does not start with `$`
	ErrExpectedRoot = errors.New("expected root selector '$'")

	// ErrUnexpectedToken indicates invalid token ordering or placement
	ErrUnexpectedToken = errors.New("unexpected token")

	// ErrUnterminatedString indicates a quoted string was not closed
	ErrUnterminatedString = errors.New("unterminated string")

	// ErrBadEscape indicates an invalid escape sequence in a string literal
	ErrBadEscape = errors.New("invalid escape sequence")

	// ErrBadNumber indicates an invalid numeric literal
	ErrBadNumber = errors.New("invalid number")

	// ErrBadSlice indicates an invalid array slice selector
	ErrBadSlice = errors.New("invalid slice selector")

	// ErrBadFunc indicates an invalid function invocation in a filter
	ErrBadFunc = errors.New("invalid function call")
)
View Source
var (
	// ErrUnknownFunc indicates a function name is not registered
	ErrUnknownFunc = errors.New("unknown function")

	// ErrBadFuncName indicates a function name is invalid
	ErrBadFuncName = errors.New("invalid function name")

	// ErrBadFuncDefinition indicates a function definition is invalid
	ErrBadFuncDefinition = errors.New("invalid function definition")

	// ErrFuncExists indicates a function was already registered
	ErrFuncExists = errors.New("function already registered")
)
View Source
var (
	// ErrLiteralMustBeCompared is raised for bare literals in logical context
	ErrLiteralMustBeCompared = errors.New("literal must be compared")

	// ErrCompRequiresSingularQuery is raised for non-singular comparisons
	ErrCompRequiresSingularQuery = errors.New(
		"comparison requires singular query",
	)

	// ErrInvalidFuncArity is raised when function arity is invalid
	ErrInvalidFuncArity = errors.New("invalid function arity")

	// ErrFuncResultMustBeCompared is raised for logical use without compare
	ErrFuncResultMustBeCompared = errors.New(
		"function result must be compared",
	)

	// ErrFuncResultMustNotBeCompared is raised for prohibited comparisons
	ErrFuncResultMustNotBeCompared = errors.New(
		"function result must not be compared",
	)

	// ErrFuncRequiresSingularQuery is raised for singular-path requirements
	ErrFuncRequiresSingularQuery = errors.New(
		"function requires singular query",
	)

	// ErrFuncRequiresQueryArgument is raised for query-arg requirements
	ErrFuncRequiresQueryArgument = errors.New(
		"function requires query argument",
	)
)

Functions

func MustQuery

func MustQuery(query string, document any) []any

MustQuery parses and compiles a JSONPath query, then runs it or panics

func Query

func Query(query string, document any) ([]any, error)

Query parses and compiles a JSONPath query, then runs it on a document

Types

type BinaryExpr

type BinaryExpr struct {
	Op          string
	Left, Right FilterExpr
}

BinaryExpr is a binary filter expression

type Compiler

type Compiler struct {
	// contains filtered or unexported fields
}

Compiler compiles parsed JSONPath syntax trees into runnable programs

func NewCompiler

func NewCompiler() *Compiler

NewCompiler creates a new Compiler

func (*Compiler) Compile

func (c *Compiler) Compile(path *PathExpr) (Path, error)

Compile compiles a parsed PathExpr into an executable Path

type Evaluator

type Evaluator func(args []*Value) *Value

Evaluator evaluates wrapped arguments and returns a wrapped result

func WrapFunction

func WrapFunction(fn Function) Evaluator

WrapFunction wraps a scalar function as an evaluator

type FilterCtx

type FilterCtx struct {
	Root    any
	Current any
}

type FilterExpr

type FilterExpr interface {
	// contains filtered or unexported methods
}

FilterExpr is the marker interface for filter AST nodes

type FilterFunc

type FilterFunc func(*FilterCtx) *Value

func And

func And(left, right FilterFunc) FilterFunc

And builds a logical-AND filter function with short-circuit behavior

func Call

func Call(evaluator Evaluator, args ...FilterFunc) FilterFunc

Call builds a filter function from a function evaluator and arguments

func Eq

func Eq(left, right FilterFunc) FilterFunc

Eq builds an equality comparison filter function

func Ge

func Ge(left, right FilterFunc) FilterFunc

Ge builds a greater-than-or-equal comparison filter function

func Gt

func Gt(left, right FilterFunc) FilterFunc

Gt builds a greater-than comparison filter function

func Le

func Le(left, right FilterFunc) FilterFunc

Le builds a less-than-or-equal comparison filter function

func Literal

func Literal(value any) FilterFunc

Literal builds a filter function that returns a scalar literal value

func Lt

func Lt(left, right FilterFunc) FilterFunc

Lt builds a less-than comparison filter function

func Ne

func Ne(left, right FilterFunc) FilterFunc

Ne builds an inequality comparison filter function

func Not

func Not(expr FilterFunc) FilterFunc

Not builds a negation filter function

func Or

func Or(left, right FilterFunc) FilterFunc

Or builds a logical-OR filter function with short-circuit behavior

func PathCurrent

func PathCurrent(path Path) FilterFunc

PathCurrent builds a filter function that queries from the current node

func PathRoot

func PathRoot(path Path) FilterFunc

PathRoot builds a filter function that queries from the root node

type FuncExpr

type FuncExpr struct {
	Name string
	Args []FilterExpr
}

FuncExpr is a filter function call expression

type Function

type Function func(args ...any) (any, bool)

Function evaluates scalar arguments and returns a scalar result

type FunctionDefinition

type FunctionDefinition struct {
	Validate Validator
	Eval     Evaluator
}

FunctionDefinition describes a filter function implementation

type FunctionUse

type FunctionUse uint8

FunctionUse describes where a function appears in filter validation

const (
	FunctionUseLogical FunctionUse = iota
	FunctionUseComparisonOperand
	FunctionUseArgument
)

type LiteralExpr

type LiteralExpr struct {
	Value any
}

LiteralExpr is a scalar literal in a filter expression

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser parses JSONPath query strings into an inspectable syntax tree

func (*Parser) Parse

func (p *Parser) Parse(query string) (*PathExpr, error)

Parse parses a JSONPath query into a PathExpr syntax tree

type Path

type Path func(document any) []any

Path is a compiled query function chain. Calling it executes the query against a JSON document

func Compile

func Compile(path *PathExpr) (Path, error)

Compile compiles a parsed PathExpr into an executable Path

func ComposePath

func ComposePath(segments ...SegmentFunc) Path

ComposePath composes segment functions into an executable Path

func MustCompile

func MustCompile(path *PathExpr) Path

MustCompile compiles a parsed PathExpr or panics

type PathExpr

type PathExpr struct {
	Segments []*SegmentExpr
}

PathExpr is a parsed JSONPath expression

func MustParse

func MustParse(query string) *PathExpr

MustParse parses a JSONPath query or panics

func Parse

func Parse(query string) (*PathExpr, error)

Parse parses a JSONPath query into a PathExpr syntax tree

type PathValueExpr

type PathValueExpr struct {
	Absolute bool
	Path     *PathExpr
}

PathValueExpr is a root or current-node relative path in a filter

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry stores function definitions and owns parse/compile/query methods

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a registry with default JSONPath functions

func (*Registry) Clone

func (r *Registry) Clone() *Registry

Clone makes an isolated copy of this registry

func (*Registry) Compile

func (r *Registry) Compile(path *PathExpr) (Path, error)

Compile compiles a parsed syntax tree into an executable Path

func (*Registry) MustCompile

func (r *Registry) MustCompile(path *PathExpr) Path

MustCompile compiles a parsed syntax tree or panics

func (*Registry) MustParse

func (r *Registry) MustParse(query string) *PathExpr

MustParse parses a query string or panics

func (*Registry) MustQuery

func (r *Registry) MustQuery(query string, document any) []any

MustQuery parses and compiles a query string, then runs it or panics

func (*Registry) MustRegisterDefinition

func (r *Registry) MustRegisterDefinition(
	name string, def *FunctionDefinition,
) *Registry

MustRegisterDefinition registers a function definition or panics

func (*Registry) MustRegisterFunction

func (r *Registry) MustRegisterFunction(
	name string, arity int, fn Function,
) *Registry

MustRegisterFunction registers a scalar function or panics

func (*Registry) Parse

func (r *Registry) Parse(query string) (*PathExpr, error)

Parse parses a query string into a syntax tree

func (*Registry) Query

func (r *Registry) Query(query string, document any) ([]any, error)

Query parses and compiles a query string, then runs it on a document

func (*Registry) RegisterDefinition

func (r *Registry) RegisterDefinition(
	name string, def *FunctionDefinition,
) error

RegisterDefinition registers a named function definition in this registry

func (*Registry) RegisterFunction

func (r *Registry) RegisterFunction(name string, arity int, fn Function) error

RegisterFunction registers a singular-arg scalar function

type SegmentExpr

type SegmentExpr struct {
	Descendant bool
	Selectors  []*SelectorExpr
}

SegmentExpr is one child or descendant traversal segment

type SegmentFunc

type SegmentFunc func(in []any, root any) []any

SegmentFunc processes input nodes and returns output nodes for one segment step

func ChildSegment

func ChildSegment(selectors ...SelectorFunc) SegmentFunc

ChildSegment builds a non-descendant segment from selector functions

func DescendantSegment

func DescendantSegment(selectors ...SelectorFunc) SegmentFunc

DescendantSegment builds a descendant segment from selector functions

type SelectorExpr

type SelectorExpr struct {
	Kind   SelectorKind
	Name   string
	Index  int
	Slice  *SliceExpr
	Filter FilterExpr
}

SelectorExpr is one bracket or dot selector operation

type SelectorFunc

type SelectorFunc func(out []any, node, root any) []any

SelectorFunc appends selected output nodes for one input node

func MakeSelectorArrayAll

func MakeSelectorArrayAll(_ *SlicePlan) SelectorFunc

MakeSelectorArrayAll builds a selector for selectorCaseArrayAll

func MakeSelectorB00

func MakeSelectorB00(plan *SlicePlan) SelectorFunc

MakeSelectorB00 builds a selector for selectorCaseB00

func MakeSelectorB01N

func MakeSelectorB01N(plan *SlicePlan) SelectorFunc

MakeSelectorB01N builds a selector for selectorCaseB01N

func MakeSelectorB01P

func MakeSelectorB01P(plan *SlicePlan) SelectorFunc

MakeSelectorB01P builds a selector for selectorCaseB01P

func MakeSelectorB10N

func MakeSelectorB10N(plan *SlicePlan) SelectorFunc

MakeSelectorB10N builds a selector for selectorCaseB10N

func MakeSelectorB10P

func MakeSelectorB10P(plan *SlicePlan) SelectorFunc

MakeSelectorB10P builds a selector for selectorCaseB10P

func MakeSelectorB11NN

func MakeSelectorB11NN(plan *SlicePlan) SelectorFunc

MakeSelectorB11NN builds a selector for selectorCaseB11NN

func MakeSelectorB11NP

func MakeSelectorB11NP(plan *SlicePlan) SelectorFunc

MakeSelectorB11NP builds a selector for selectorCaseB11NP

func MakeSelectorB11PN

func MakeSelectorB11PN(plan *SlicePlan) SelectorFunc

MakeSelectorB11PN builds a selector for selectorCaseB11PN

func MakeSelectorB11PP

func MakeSelectorB11PP(plan *SlicePlan) SelectorFunc

MakeSelectorB11PP builds a selector for selectorCaseB11PP

func MakeSelectorF00

func MakeSelectorF00(plan *SlicePlan) SelectorFunc

MakeSelectorF00 builds a selector for selectorCaseF00

func MakeSelectorF01N

func MakeSelectorF01N(plan *SlicePlan) SelectorFunc

MakeSelectorF01N builds a selector for selectorCaseF01N

func MakeSelectorF01P

func MakeSelectorF01P(plan *SlicePlan) SelectorFunc

MakeSelectorF01P builds a selector for selectorCaseF01P

func MakeSelectorF10N

func MakeSelectorF10N(plan *SlicePlan) SelectorFunc

MakeSelectorF10N builds a selector for selectorCaseF10N

func MakeSelectorF10P

func MakeSelectorF10P(plan *SlicePlan) SelectorFunc

MakeSelectorF10P builds a selector for selectorCaseF10P

func MakeSelectorF11NN

func MakeSelectorF11NN(plan *SlicePlan) SelectorFunc

MakeSelectorF11NN builds a selector for selectorCaseF11NN

func MakeSelectorF11NP

func MakeSelectorF11NP(plan *SlicePlan) SelectorFunc

MakeSelectorF11NP builds a selector for selectorCaseF11NP

func MakeSelectorF11PN

func MakeSelectorF11PN(plan *SlicePlan) SelectorFunc

MakeSelectorF11PN builds a selector for selectorCaseF11PN

func MakeSelectorF11PP

func MakeSelectorF11PP(plan *SlicePlan) SelectorFunc

MakeSelectorF11PP builds a selector for selectorCaseF11PP

func SelectFilter

func SelectFilter(filter FilterFunc) SelectorFunc

SelectFilter builds a selector for filter-based child selection

func SelectIndex

func SelectIndex(index int) SelectorFunc

SelectIndex builds a selector for array element lookup by index

func SelectName

func SelectName(name string) SelectorFunc

SelectName builds a selector for object-member lookup by name

func SelectSlice

func SelectSlice(s *SliceExpr) SelectorFunc

SelectSlice builds a selector for array slice selection

func SelectWildcard

func SelectWildcard() SelectorFunc

SelectWildcard builds a selector for wildcard child selection

type SelectorKind

type SelectorKind uint8

SelectorKind identifies the selector variant in SelectorExpr

const (
	SelectorName     SelectorKind = iota // object member by name
	SelectorIndex                        // array index
	SelectorWildcard                     // all direct child values
	SelectorSlice                        // array elements by slice bounds
	SelectorFilter                       // child values by filter predicate
)

type SliceExpr

type SliceExpr struct {
	HasStart bool
	Start    int
	HasEnd   bool
	End      int
	Step     int
}

SliceExpr stores parsed slice bounds and step

type SlicePlan

type SlicePlan struct {
	Start int
	End   int
	Step  int
}

SlicePlan stores precompiled bounds for slice selection

type UnaryExpr

type UnaryExpr struct {
	Op   string
	Expr FilterExpr
}

UnaryExpr is a unary filter expression

type Validator

type Validator func(args []FilterExpr, use FunctionUse, inComparison bool) error

Validator validates function arguments for a call site

type Value

type Value struct {
	IsNodes bool
	Scalar  any
	Nodes   []any
}

Value stores either a scalar or node list argument/result

func NodesValue

func NodesValue(v []any) *Value

NodesValue constructs a node-list filter value

func ScalarValue

func ScalarValue(value any) *Value

ScalarValue constructs a scalar filter value

func (*Value) Count

func (v *Value) Count() int

Count reports the number of candidates this value contributes to filter comparisons. For node values, this is len(Nodes). For scalar values, this is always 1

func (*Value) IsNothing

func (v *Value) IsNothing() bool

IsNothing reports whether this value is the internal "nothing" sentinel. A node-list value is nothing only when it contains exactly one sentinel

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL