npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@eurfelux/jq-js

v0.3.0

Published

A pure TypeScript implementation of jq, the JSON processor

Readme

jq-js

A pure TypeScript implementation of jq, the JSON processor. Zero native dependencies, full ESM + CJS support.

Why?

| | jq-js | node-jq | jq-wasm | jsonata | |---|---|---|---|---| | Implementation | Pure TypeScript | Shells out to jq binary | WASM (C → Emscripten) | Pure JavaScript | | jq syntax | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: (own DSL) | | ESM support | :white_check_mark: type: "module" + exports | :x: CJS only | :x: No exports | :warning: No type: "module" | | Browser | :white_check_mark: | :x: Node only | :white_check_mark: | :white_check_mark: | | Native deps | None | Requires jq installed | WASM binary (~1.4MB) | None | | Tree-shakeable | :white_check_mark: | :x: | :x: | :x: | | TypeScript | Written in TS, ships .d.ts | @types/node-jq | Minimal types | Ships .d.ts | | Bundle size | ~85KB (~21KB gzip) | N/A (native) | ~1.4MB (~500KB gzip) | ~74KB (~23KB gzip) |

jq-js is the only option that combines real jq syntax, pure JS (no WASM/native), and proper ESM with type: "module" and conditional exports.

Install

pnpm add @eurfelux/jq-js
# or
npm install @eurfelux/jq-js
# or
yarn add @eurfelux/jq-js

Usage

import { jq } from "@eurfelux/jq-js";

// Basic field access
jq(".name", { name: "Alice", age: 30 });
// => ["Alice"]

// Array operations
jq("[.[] | select(. > 2)]", [1, 2, 3, 4, 5]);
// => [[3, 4, 5]]

// Pipe and transform
jq(".users[] | {name, email}", {
  users: [
    { name: "Alice", email: "[email protected]", role: "admin" },
    { name: "Bob", email: "[email protected]", role: "user" },
  ],
});
// => [{name: "Alice", email: "[email protected]"}, {name: "Bob", email: "[email protected]"}]

// String interpolation
jq('"Hello \\(.name), you are \\(.age) years old"', { name: "Alice", age: 30 });
// => ["Hello Alice, you are 30 years old"]

// Reduce
jq("reduce .[] as $x (0; . + $x)", [1, 2, 3, 4, 5]);
// => [15]

Advanced API

For more control, you can access individual pipeline stages:

import { lex, parse, compile } from "@eurfelux/jq-js";

// Tokenize
const tokens = lex(".foo | map(. + 1)");

// Parse to AST
const ast = parse(tokens);

// Compile to reusable filter function
const filter = compile(ast);
filter({ foo: [1, 2, 3] }); // => [[2, 3, 4]]
filter({ foo: [10, 20] }); // => [[11, 21]]

Supported Features

Core Syntax

| Feature | Syntax | Status | |---------|--------|--------| | Identity | . | :white_check_mark: | | Field access | .foo, ."foo", .foo.bar | :white_check_mark: | | Array index/slice | .[0], .[-1], .[2:5] | :white_check_mark: | | Iteration | .[] | :white_check_mark: | | Pipe | \| | :white_check_mark: | | Comma | .a, .b | :white_check_mark: | | Parentheses | (expr) | :white_check_mark: | | Recursive descent | .. | :white_check_mark: | | Optional | .foo? | :white_check_mark: | | Try-catch | try expr catch handler | :white_check_mark: | | Conditionals | if-then-elif-else-end | :white_check_mark: | | String interpolation | "Hello \(.name)" | :white_check_mark: | | Alternative | //, ?// | :white_check_mark: | | Arithmetic | + - * / % | :white_check_mark: | | Comparison | == != < > <= >= | :white_check_mark: | | Logic | and or not | :white_check_mark: | | Array/object construction | [expr], {key: expr} | :white_check_mark: | | Variable binding | expr as $x \| body | :white_check_mark: | | Destructuring | as [$a, $b], as {k: $v} | :white_check_mark: | | Reduce | reduce .[] as $x (init; update) | :white_check_mark: | | Foreach | foreach .[] as $x (init; update; extract) | :white_check_mark: | | Label-break | label $out \| ... break $out | :white_check_mark: | | User-defined functions | def name(args): body; | :white_check_mark: | | Update operators | \|= += -= *= /= %= //= = | :white_check_mark: |

Built-in Functions

Type & Inspection: type, length, utf8bytelength, keys, values, has, contains, inside, builtins

Transform: map, map_values, select, empty, add, any, all, flatten, range, reverse, sort, sort_by, group_by, unique, unique_by, min, max, min_by, max_by, limit, first, last, nth, skip, pick, isempty, transpose, bsearch, INDEX, IN

String: tostring, tonumber, toboolean, tojson, fromjson, ascii_downcase, ascii_upcase, ltrimstr, rtrimstr, trimstr, trim, ltrim, rtrim, startswith, endswith, split, join, explode, implode, index, rindex, indices

Regex: test, match, capture, scan, sub, gsub, splits

Object: to_entries, from_entries, with_entries, keys_unsorted

Path: path, paths, getpath, setpath, delpaths, leaf_paths, del

Math: floor, ceil, round, sqrt, fabs, abs, pow, log, log2, log10, exp, exp2, sin, cos, tan, asin, acos, atan, nan, infinite, isnan, isinfinite, isfinite, isnormal

Date/Time: now, gmtime, mktime, strftime, strptime, strflocaltime, todate, fromdate, date, dateadd, datesub

Control: recurse, walk, until, while, repeat, error, debug, env, $ENV

Type filters: arrays, objects, numbers, strings, booleans, nulls, scalars, iterables, values

Format Strings: @base64, @base64d, @html, @csv, @tsv, @json, @uri, @urid, @text, @sh

Date/Time: now, gmtime, mktime, strftime, strptime, todate, fromdate, dateadd, datesub

Additional: try-alternative (?//), $ENV / env, bsearch, transpose, INDEX, IN, pick, isempty, trim / ltrim / rtrim, toboolean, skip

Compatibility

jq-js passes 531 of 555 official jq test cases (95.7%). The remaining gaps are:

Not Supported

| Feature | Reason | |---------|--------| | import / include (module system) | Requires filesystem access; not available in browsers. Parser accepts the syntax but runtime throws an error. | | Arbitrary precision numbers (have_decnum) | JavaScript uses IEEE 754 doubles. Numbers beyond Number.MAX_SAFE_INTEGER lose precision. Values like 1E+1000 become Infinity. | | input / inputs (streaming) | Not applicable — jq-js processes a single input value. |

Known Limitations

| Feature | Issue | Workaround | |---------|-------|------------| | Recursive update (.. \| select(cond)) \|= expr | Complex path updates through recursive descent are not fully supported | Use path(.. \| select(cond)) with setpath/getpath | | getpath(p) \|= expr | Update-through-getpath not implemented | Use setpath(p; getpath(p) \| expr) | | Regex gn flag | The n flag (no-capture for unnamed groups) is not supported | Use named capture groups (?<name>...) | | Regex Unicode \b | JavaScript's \b does not support multi-codepoint graphemes (e.g. flag emoji) | Use explicit character classes | | Optional capture groups | JS regex returns null for non-participating groups; jq (Oniguruma) returns "" | Check for both null and "" in downstream code |

Error Handling

jq-js provides typed errors for each pipeline stage:

import { jq, JqLexError, JqParseError, JqRuntimeError } from "@eurfelux/jq-js";

try {
  jq("invalid $$$ filter", null);
} catch (e) {
  if (e instanceof JqLexError) console.log("Tokenization failed:", e.message);
  if (e instanceof JqParseError) console.log("Parse failed:", e.message);
  if (e instanceof JqRuntimeError) console.log("Runtime error:", e.message);
}

Module Formats

jq-js ships with dual ESM + CJS builds and full TypeScript declarations:

{
  "import": "./dist/index.mjs",
  "require": "./dist/index.cjs",
  "types": "./dist/index.d.mts"
}

Development

pnpm install
pnpm run build        # Build ESM + CJS
pnpm run test         # Run e2e tests
pnpm run test:all     # Run all tests (including official jq test suite)
pnpm run typecheck    # TypeScript type check
pnpm run lint         # oxlint
pnpm run fmt          # oxfmt format

Acknowledgments

This project is inspired by and references the jq implementation, licensed under the MIT License (Copyright (c) 2012 Stephen Dolan). jq's documentation is licensed under CC BY 3.0.

License

MIT