micro-jq

A small TypeScript implementation of jq's filter syntax for querying and transforming JSON in the browser and Node.

Library
npm
v2.0.2
29stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
48/100Fair
Development Activity56
Maintenance44
Community20
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
65/100Good
Architecture78
Code Quality85
Innovation62
Learning Curve35

@elastic/micro-jq is a compact reimplementation of jq’s filter language for JavaScript environments, built specifically for cases where the real jq binary isn’t available — most notably the browser, where a C program can’t run. It parses a subset of jq syntax into a typed sequence of op codes using a PEG grammar (via Peggy), then interprets that op code list against a JSON value to produce filtered or transformed output, all in pure TypeScript with a single runtime dependency.

The library targets simple, user-supplied filtering jobs rather than full jq compatibility: indexing, slicing, piping, object/array construction, comparisons, and a handful of string and collection functions (keys, length, split, join, trim, from_entries) are supported, with jq’s ? optional/strict semantics preserved per operation. It ships as dual ESM/CJS builds with type definitions, plus a minimal CLI for scripting use outside the browser.

What You Get

  • A parse-then-execute pipeline: jq scripts compile to a typed OpCode array via a Peggy-generated parser, then run through a stateless interpreter
  • Core jq operators — property/index access, slicing, piping, object/array construction, comparisons, and boolean logic — with strict/optional (?) semantics matching real jq
  • Built-in functions: keys, length, split, join, startswith/endswith, ltrimstr/rtrimstr, trim/ltrim/rtrim, from_entries
  • Dual ESM/CJS builds with bundled TypeScript type definitions and zero external runtime dependencies (its one dependency, string-length, is inlined at build time)
  • A checkScript helper to validate a jq filter string without executing it, useful for validating user-supplied filters before running them
  • A small CLI (microjq) for piping JSON through a filter from the command line

Common Use Cases

  • Letting end users define custom JSON filters in a browser-based UI (e.g. a log viewer or API explorer) without running arbitrary code
  • Client-side transformation of API responses using a familiar jq-like syntax instead of hand-written JS reducers
  • Validating jq filter syntax server-side before persisting a saved view or alert rule
  • Lightweight JSON post-processing in Node.js scripts or CLIs where installing the native jq binary isn’t desirable

Under The Hood

Architecture parser.pegjs (compiled via Peggy with the ts-pegjs plugin) turns a subset of jq’s filter syntax into a typed array of OpCode objects, and execute.ts’s evaluateOpCodes runs a single switch/reduce loop that threads a Context (an array of JSON values) through each op code in order; pipe/select/create_object/create_array cases recursively invoke evaluateOpCodes for their nested branches and coordinate via an internal ‘exploder’ callback protocol so that operations producing zero, one, or many values flatten correctly downstream. The interpreter is stateless — no persistent parser or interpreter instance is kept between calls — so the bundled CLI is just a thin two-step wrapper that reads JSON from stdin and calls executeScript. This is a compact, cleanly separated monolith (grammar vs. interpreter) with no plugin or extension mechanism, so adding a new jq operator means touching both the grammar and the interpreter directly.

Tech Stack Written entirely in TypeScript, targeting Node >=20, with Peggy generating a typed parser from parser.pegjs at build time via ts-pegjs. The one runtime dependency, string-length, is inlined into both output bundles by tsup’s noExternal option, so consumers install nothing extra. tsup produces separate ESM (.mjs) and CJS builds with bundled .d.ts/.d.mts declarations. Testing runs on Jest with ts-jest; linting uses a flat ESLint config (typescript-eslint, eslint-plugin-jest, eslint-plugin-prettier) alongside Prettier. CI runs the full lint/build/test chain across Node 20, 22, and 24 in GitHub Actions, with a separate tag-triggered, OIDC-authenticated npm publish workflow.

Code Quality Two large Jest suites (roughly 670 and 750 lines) exercise both the grammar’s parsing edge cases and the interpreter’s evaluation semantics — negative and out-of-bounds indices, slicing, explode/select filtering, from_entries variants, and more. Error handling is explicit throughout: every evaluator branch throws a descriptive Error on type mismatches, gated by a per-op strict flag that mirrors jq’s ? optional operator, letting pick/index/slice/explode either throw or silently skip depending on context. Types are modeled as a single discriminated OpCode union covering every operator shape, with a deliberate @ts-expect-error in the default switch branch acting as an exhaustiveness check. npm test chains lint, build, and Jest, and CI enforces all three on every push and pull request.

API Design The public surface is intentionally minimal — two exports, checkScript and executeScript(input, script) — requiring no setup or configuration to use, plus a microjq CLI binary for immediate command-line use. This keeps the developer experience low-friction for the library’s narrow purpose. Documentation is thin, though: the README explains the motivation but not the supported operator subset or usage examples, so new consumers largely learn the syntax coverage by reading the test suite. The design isn’t conceptually novel — it’s a deliberately partial jq reimplementation for environments where the native binary can’t run — but its op-code/exploder protocol for correctly propagating jq’s array-explosion semantics through nested pipes and object/array construction reflects non-trivial care.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search