jq for Go

github.com/malcolmston/jq

The jq query language, embedded in Go — lexer, parser, evaluator.

 GitHubports jqlang/jq

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

shell
$ go get github.com/malcolmston/jq

Quick start

main.go
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 $x bindings, label, and user-defined functions def 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 @sh format 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 — Eval for one-shot use, Compile once and Run many times, RunFunc to consume outputs as they are produced and stop early, and WithVariables to bind $name values
  • Values are plain Go values — nil, bool, float64, string, []any, map[string]any — so results drop straight into encoding/json code
  • jq's own ordering rules for sort and comparison: null < false < true < numbers < strings < arrays < objects
  • CompileError carries the program and the byte offset of the problem; RuntimeError carries what a jq error(…) would print — both matchable with errors.Is
  • Bounded execution — a step and depth budget the program's own try cannot catch, so a runaway repeat or recurse cannot wedge a server; tunable with WithMaxSteps
  • Zero dependencies — pure Go standard library, no cgo
jq