jq for Go
The jq query language, embedded in Go — lexer, parser, evaluator.
A full implementation of the jq 1.7 query language built entirely on the Go standard library — no third-party modules, no cgo, no require directives. The defining property of jq is that every expression is a <i>generator</i> producing zero or more outputs, so the evaluator is continuation-passing: <code>empty</code>, <code>limit</code>, <code>first</code>, <code>//</code> and backtracking all fall out of that shape rather than being special-cased. Values and paths are unified, so one evaluator serves both <code>.a.b</code> and <code>path(.a.b)</code>, which is what makes <code>|=</code>, <code>del</code> and the assignment operators correct. Around 120 builtins are themselves written in jq and parsed at init, so they compose as generators and inside path expressions exactly as upstream's do. The import path is github.com/malcolmston/jq.
Install
$ go get github.com/malcolmston/jqQuick start
import "github.com/malcolmston/jq"
input, _ := jq.Unmarshal([]byte(
`{"users":[{"name":"ada","age":36},{"name":"bob","age":24}]}`))
out, err := jq.Eval(".users | map(select(.age > 30) | .name)", input)
if err != nil { log.Fatal(err) }
fmt.Println(out[0]) <span class="tok-c">// [ada]
<span class="tok-c">// Assignment works because paths and values share one evaluator
updated, _ := jq.Eval("(.[] | select(. >= 2)) |= . * 10",
[]any{1.0, 2.0, 3.0}) <span class="tok-c">// [1 20 30]Features
- Language core — identity, field access, indexing, slicing
.[2:5], iteration.[], pipe, comma, the alternative operator//, arithmetic and comparison,and/or/not, optional access? - Control flow —
if/then/elif/else/end,try/catch,reduce,foreach,as $xbindings,label, and user-defined functionsdef f(a; b): …;with generator arguments and recursion - Construction — object and array literals, string interpolation
"\(…)", and the@base64 @base64d @csv @tsv @html @uri @json @text @shformat strings, usable bare or as interpolation prefixes - Paths and updates — path expressions,
getpath/setpath/delpaths/del, and all eight assignment operators=,|=,+=,-=,*=,/=,%=,//= - Roughly 120 builtins covering sequences, objects, strings, math, regex, dates and paths
- Streaming API —
Evalfor one-shot use,Compileonce andRunmany times,RunFuncto consume outputs as they are produced and stop early, andWithVariablesto bind$namevalues - Values are plain Go values —
nil,bool,float64,string,[]any,map[string]any— so results drop straight intoencoding/jsoncode - jq's own ordering rules for
sortand comparison: null < false < true < numbers < strings < arrays < objects CompileErrorcarries the program and the byte offset of the problem;RuntimeErrorcarries what a jqerror(…)would print — both matchable witherrors.Is- Bounded execution — a step and depth budget the program's own
trycannot catch, so a runawayrepeatorrecursecannot wedge a server; tunable withWithMaxSteps - Zero dependencies — pure Go standard library, no cgo